diff options
Diffstat (limited to 'lib/utils')
-rw-r--r-- | lib/utils/__tests__/git.js | 57 | ||||
-rw-r--r-- | lib/utils/__tests__/location.js | 100 | ||||
-rw-r--r-- | lib/utils/__tests__/path.js | 17 | ||||
-rw-r--r-- | lib/utils/command.js | 118 | ||||
-rw-r--r-- | lib/utils/error.js | 99 | ||||
-rw-r--r-- | lib/utils/fs.js | 170 | ||||
-rw-r--r-- | lib/utils/genKey.js | 13 | ||||
-rw-r--r-- | lib/utils/git.js | 133 | ||||
-rw-r--r-- | lib/utils/images.js | 60 | ||||
-rw-r--r-- | lib/utils/location.js | 139 | ||||
-rw-r--r-- | lib/utils/logger.js | 172 | ||||
-rw-r--r-- | lib/utils/mergeDefaults.js | 16 | ||||
-rw-r--r-- | lib/utils/path.js | 74 | ||||
-rw-r--r-- | lib/utils/promise.js | 148 | ||||
-rw-r--r-- | lib/utils/reducedObject.js | 33 | ||||
-rw-r--r-- | lib/utils/timing.js | 97 |
16 files changed, 0 insertions, 1446 deletions
diff --git a/lib/utils/__tests__/git.js b/lib/utils/__tests__/git.js deleted file mode 100644 index abc1ea1..0000000 --- a/lib/utils/__tests__/git.js +++ /dev/null @@ -1,57 +0,0 @@ -var path = require('path'); -var os = require('os'); - -var Git = require('../git'); - -describe('Git', function() { - - describe('URL parsing', function() { - - it('should correctly validate git urls', function() { - // HTTPS - expect(Git.isUrl('git+https://github.com/Hello/world.git')).toBeTruthy(); - - // SSH - expect(Git.isUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1')).toBeTruthy(); - - // Non valid - expect(Git.isUrl('https://github.com/Hello/world.git')).toBeFalsy(); - expect(Git.isUrl('README.md')).toBeFalsy(); - }); - - it('should parse HTTPS urls', function() { - var parts = Git.parseUrl('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md'); - - expect(parts.host).toBe('https://gist.github.com/69ea4542e4c8967d2fa7.git'); - expect(parts.ref).toBe(null); - expect(parts.filepath).toBe('test.md'); - }); - - it('should parse HTTPS urls with a reference', function() { - var parts = Git.parseUrl('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md#1.0.0'); - - expect(parts.host).toBe('https://gist.github.com/69ea4542e4c8967d2fa7.git'); - expect(parts.ref).toBe('1.0.0'); - expect(parts.filepath).toBe('test.md'); - }); - - it('should parse SSH urls', function() { - var parts = Git.parseUrl('git+git@github.com:GitbookIO/gitbook.git/directory/README.md#e1594cde2c32e4ff48f6c4eff3d3d461743d74e1'); - - expect(parts.host).toBe('git@github.com:GitbookIO/gitbook.git'); - expect(parts.ref).toBe('e1594cde2c32e4ff48f6c4eff3d3d461743d74e1'); - expect(parts.filepath).toBe('directory/README.md'); - }); - }); - - describe('Cloning and resolving', function() { - it('should clone an HTTPS url', function() { - var git = new Git(path.join(os.tmpdir(), 'test-git-'+Date.now())); - return git.resolve('git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md') - .then(function(filename) { - expect(path.extname(filename)).toBe('.md'); - }); - }); - }); - -}); diff --git a/lib/utils/__tests__/location.js b/lib/utils/__tests__/location.js deleted file mode 100644 index 822338e..0000000 --- a/lib/utils/__tests__/location.js +++ /dev/null @@ -1,100 +0,0 @@ -var LocationUtils = require('../location'); - -describe('LocationUtils', function() { - it('should correctly test external location', function() { - expect(LocationUtils.isExternal('http://google.fr')).toBe(true); - expect(LocationUtils.isExternal('https://google.fr')).toBe(true); - expect(LocationUtils.isExternal('test.md')).toBe(false); - expect(LocationUtils.isExternal('folder/test.md')).toBe(false); - expect(LocationUtils.isExternal('/folder/test.md')).toBe(false); - expect(LocationUtils.isExternal('data:image/png')).toBe(false); - }); - - it('should correctly test data:uri location', function() { - expect(LocationUtils.isDataURI('data:image/png')).toBe(true); - expect(LocationUtils.isDataURI('http://google.fr')).toBe(false); - expect(LocationUtils.isDataURI('https://google.fr')).toBe(false); - expect(LocationUtils.isDataURI('test.md')).toBe(false); - expect(LocationUtils.isDataURI('data.md')).toBe(false); - }); - - it('should correctly detect anchor location', function() { - expect(LocationUtils.isAnchor('#test')).toBe(true); - expect(LocationUtils.isAnchor(' #test')).toBe(true); - expect(LocationUtils.isAnchor('https://google.fr#test')).toBe(false); - expect(LocationUtils.isAnchor('test.md#test')).toBe(false); - }); - - describe('.relative', function() { - it('should resolve to a relative path (same folder)', function() { - expect(LocationUtils.relative('links/', 'links/test.md')).toBe('test.md'); - }); - - it('should resolve to a relative path (parent folder)', function() { - expect(LocationUtils.relative('links/', 'test.md')).toBe('../test.md'); - }); - - it('should resolve to a relative path (child folder)', function() { - expect(LocationUtils.relative('links/', 'links/hello/test.md')).toBe('hello/test.md'); - }); - }); - - describe('.flatten', function() { - it('should remove leading slash', function() { - expect(LocationUtils.flatten('/test.md')).toBe('test.md'); - expect(LocationUtils.flatten('/hello/cool.md')).toBe('hello/cool.md'); - }); - - it('should remove leading slashes', function() { - expect(LocationUtils.flatten('///test.md')).toBe('test.md'); - }); - - it('should not break paths', function() { - expect(LocationUtils.flatten('hello/cool.md')).toBe('hello/cool.md'); - }); - }); - - describe('.toAbsolute', function() { - it('should correctly transform as absolute', function() { - expect(LocationUtils.toAbsolute('http://google.fr')).toBe('http://google.fr'); - expect(LocationUtils.toAbsolute('test.md', './', './')).toBe('test.md'); - expect(LocationUtils.toAbsolute('folder/test.md', './', './')).toBe('folder/test.md'); - }); - - it('should correctly handle windows path', function() { - expect(LocationUtils.toAbsolute('folder\\test.md', './', './')).toBe('folder/test.md'); - }); - - it('should correctly handle absolute path', function() { - expect(LocationUtils.toAbsolute('/test.md', './', './')).toBe('test.md'); - expect(LocationUtils.toAbsolute('/test.md', 'test', 'test')).toBe('../test.md'); - expect(LocationUtils.toAbsolute('/sub/test.md', 'test', 'test')).toBe('../sub/test.md'); - expect(LocationUtils.toAbsolute('/test.png', 'folder', '')).toBe('test.png'); - }); - - it('should correctly handle absolute path (windows)', function() { - expect(LocationUtils.toAbsolute('\\test.png', 'folder', '')).toBe('test.png'); - }); - - it('should resolve path starting by "/" in root directory', function() { - expect( - LocationUtils.toAbsolute('/test/hello.md', './', './') - ).toBe('test/hello.md'); - }); - - it('should resolve path starting by "/" in child directory', function() { - expect( - LocationUtils.toAbsolute('/test/hello.md', './hello', './') - ).toBe('test/hello.md'); - }); - - it('should resolve path starting by "/" in child directory, with same output directory', function() { - expect( - LocationUtils.toAbsolute('/test/hello.md', './hello', './hello') - ).toBe('../test/hello.md'); - }); - }); - -}); - - diff --git a/lib/utils/__tests__/path.js b/lib/utils/__tests__/path.js deleted file mode 100644 index 22bb016..0000000 --- a/lib/utils/__tests__/path.js +++ /dev/null @@ -1,17 +0,0 @@ -var path = require('path'); - -describe('Paths', function() { - var PathUtils = require('..//path'); - - describe('setExtension', function() { - it('should correctly change extension of filename', function() { - expect(PathUtils.setExtension('test.md', '.html')).toBe('test.html'); - expect(PathUtils.setExtension('test.md', '.json')).toBe('test.json'); - }); - - it('should correctly change extension of path', function() { - expect(PathUtils.setExtension('hello/test.md', '.html')).toBe(path.normalize('hello/test.html')); - expect(PathUtils.setExtension('hello/test.md', '.json')).toBe(path.normalize('hello/test.json')); - }); - }); -}); diff --git a/lib/utils/command.js b/lib/utils/command.js deleted file mode 100644 index 90a556e..0000000 --- a/lib/utils/command.js +++ /dev/null @@ -1,118 +0,0 @@ -var is = require('is'); -var childProcess = require('child_process'); -var spawn = require('spawn-cmd').spawn; -var Promise = require('./promise'); - -/** - Execute a command - - @param {String} command - @param {Object} options - @return {Promise} -*/ -function exec(command, options) { - var d = Promise.defer(); - - var child = childProcess.exec(command, options, function(err, stdout, stderr) { - if (!err) { - return d.resolve(); - } - - err.message = stdout.toString('utf8') + stderr.toString('utf8'); - d.reject(err); - }); - - child.stdout.on('data', function (data) { - d.notify(data); - }); - - child.stderr.on('data', function (data) { - d.notify(data); - }); - - return d.promise; -} - -/** - Spawn an executable - - @param {String} command - @param {Array} args - @param {Object} options - @return {Promise} -*/ -function spawnCmd(command, args, options) { - var d = Promise.defer(); - var child = spawn(command, args, options); - - child.on('error', function(error) { - return d.reject(error); - }); - - child.stdout.on('data', function (data) { - d.notify(data); - }); - - child.stderr.on('data', function (data) { - d.notify(data); - }); - - child.on('close', function(code) { - if (code === 0) { - d.resolve(); - } else { - d.reject(new Error('Error with command "'+command+'"')); - } - }); - - return d.promise; -} - -/** - Transform an option object to a command line string - - @param {String|number} value - @param {String} -*/ -function escapeShellArg(value) { - if (is.number(value)) { - return value; - } - - value = String(value); - value = value.replace(/"/g, '\\"'); - - return '"' + value + '"'; -} - -/** - Transform a map of options into a command line arguments string - - @param {Object} options - @return {String} -*/ -function optionsToShellArgs(options) { - var result = []; - - for (var key in options) { - var value = options[key]; - - if (value === null || value === undefined || value === false) { - continue; - } - - if (is.bool(value)) { - result.push(key); - } else { - result.push(key + '=' + escapeShellArg(value)); - } - } - - return result.join(' '); -} - -module.exports = { - exec: exec, - spawn: spawnCmd, - optionsToShellArgs: optionsToShellArgs -}; diff --git a/lib/utils/error.js b/lib/utils/error.js deleted file mode 100644 index 7686779..0000000 --- a/lib/utils/error.js +++ /dev/null @@ -1,99 +0,0 @@ -var is = require('is'); - -var TypedError = require('error/typed'); -var WrappedError = require('error/wrapped'); - - -// Enforce as an Error object, and cleanup message -function enforce(err) { - if (is.string(err)) err = new Error(err); - err.message = err.message.replace(/^Error: /, ''); - - return err; -} - -// Random error wrappers during parsing/generation -var ParsingError = WrappedError({ - message: 'Parsing Error: {origMessage}', - type: 'parse' -}); -var OutputError = WrappedError({ - message: 'Output Error: {origMessage}', - type: 'generate' -}); - -// A file does not exists -var FileNotFoundError = TypedError({ - type: 'file.not-found', - message: 'No "{filename}" file (or is ignored)', - filename: null -}); - -// A file cannot be parsed -var FileNotParsableError = TypedError({ - type: 'file.not-parsable', - message: '"{filename}" file cannot be parsed', - filename: null -}); - -// A file is outside the scope -var FileOutOfScopeError = TypedError({ - type: 'file.out-of-scope', - message: '"{filename}" not in "{root}"', - filename: null, - root: null, - code: 'EACCESS' -}); - -// A file is outside the scope -var RequireInstallError = TypedError({ - type: 'install.required', - message: '"{cmd}" is not installed.\n{install}', - cmd: null, - code: 'ENOENT', - install: '' -}); - -// Error for nunjucks templates -var TemplateError = WrappedError({ - message: 'Error compiling template "{filename}": {origMessage}', - type: 'template', - filename: null -}); - -// Error for nunjucks templates -var PluginError = WrappedError({ - message: 'Error with plugin "{plugin}": {origMessage}', - type: 'plugin', - plugin: null -}); - -// Error with the book's configuration -var ConfigurationError = WrappedError({ - message: 'Error with book\'s configuration: {origMessage}', - type: 'configuration' -}); - -// Error during ebook generation -var EbookError = WrappedError({ - message: 'Error during ebook generation: {origMessage}\n{stdout}', - type: 'ebook', - stdout: '' -}); - -module.exports = { - enforce: enforce, - - ParsingError: ParsingError, - OutputError: OutputError, - RequireInstallError: RequireInstallError, - - FileNotParsableError: FileNotParsableError, - FileNotFoundError: FileNotFoundError, - FileOutOfScopeError: FileOutOfScopeError, - - TemplateError: TemplateError, - PluginError: PluginError, - ConfigurationError: ConfigurationError, - EbookError: EbookError -}; diff --git a/lib/utils/fs.js b/lib/utils/fs.js deleted file mode 100644 index 35839a3..0000000 --- a/lib/utils/fs.js +++ /dev/null @@ -1,170 +0,0 @@ -var fs = require('graceful-fs'); -var mkdirp = require('mkdirp'); -var destroy = require('destroy'); -var rmdir = require('rmdir'); -var tmp = require('tmp'); -var request = require('request'); -var path = require('path'); -var cp = require('cp'); -var cpr = require('cpr'); - -var Promise = require('./promise'); - -// Write a stream to a file -function writeStream(filename, st) { - var d = Promise.defer(); - - var wstream = fs.createWriteStream(filename); - var cleanup = function() { - destroy(wstream); - wstream.removeAllListeners(); - }; - - wstream.on('finish', function () { - cleanup(); - d.resolve(); - }); - wstream.on('error', function (err) { - cleanup(); - d.reject(err); - }); - - st.on('error', function(err) { - cleanup(); - d.reject(err); - }); - - st.pipe(wstream); - - return d.promise; -} - -// Return a promise resolved with a boolean -function fileExists(filename) { - var d = Promise.defer(); - - fs.exists(filename, function(exists) { - d.resolve(exists); - }); - - return d.promise; -} - -// Generate temporary file -function genTmpFile(opts) { - return Promise.nfcall(tmp.file, opts) - .get(0); -} - -// Generate temporary dir -function genTmpDir(opts) { - return Promise.nfcall(tmp.dir, opts) - .get(0); -} - -// Download an image -function download(uri, dest) { - return writeStream(dest, request(uri)); -} - -// Find a filename available in a folder -function uniqueFilename(base, filename) { - var ext = path.extname(filename); - filename = path.resolve(base, filename); - filename = path.join(path.dirname(filename), path.basename(filename, ext)); - - var _filename = filename+ext; - - var i = 0; - while (fs.existsSync(filename)) { - _filename = filename + '_' + i + ext; - i = i + 1; - } - - return Promise(path.relative(base, _filename)); -} - -// Create all required folder to create a file -function ensureFile(filename) { - var base = path.dirname(filename); - return Promise.nfcall(mkdirp, base); -} - -// Remove a folder -function rmDir(base) { - return Promise.nfcall(rmdir, base, { - fs: fs - }); -} - -/** - Assert a file, if it doesn't exist, call "generator" - - @param {String} filePath - @param {Function} generator - @return {Promise} -*/ -function assertFile(filePath, generator) { - return fileExists(filePath) - .then(function(exists) { - if (exists) return; - - return generator(); - }); -} - -/** - Pick a file, returns the absolute path if exists, undefined otherwise - - @param {String} rootFolder - @param {String} fileName - @return {String} -*/ -function pickFile(rootFolder, fileName) { - var result = path.join(rootFolder, fileName); - if (fs.existsSync(result)) { - return result; - } - - return undefined; -} - -/** - Ensure that a directory exists and is empty - - @param {String} folder - @return {Promise} -*/ -function ensureFolder(rootFolder) { - return rmDir(rootFolder) - .fail(function() { - return Promise(); - }) - .then(function() { - return Promise.nfcall(mkdirp, rootFolder); - }); -} - -module.exports = { - exists: fileExists, - existsSync: fs.existsSync, - mkdirp: Promise.nfbind(mkdirp), - readFile: Promise.nfbind(fs.readFile), - writeFile: Promise.nfbind(fs.writeFile), - assertFile: assertFile, - pickFile: pickFile, - stat: Promise.nfbind(fs.stat), - statSync: fs.statSync, - readdir: Promise.nfbind(fs.readdir), - writeStream: writeStream, - readStream: fs.createReadStream, - copy: Promise.nfbind(cp), - copyDir: Promise.nfbind(cpr), - tmpFile: genTmpFile, - tmpDir: genTmpDir, - download: download, - uniqueFilename: uniqueFilename, - ensureFile: ensureFile, - ensureFolder: ensureFolder, - rmDir: rmDir -}; diff --git a/lib/utils/genKey.js b/lib/utils/genKey.js deleted file mode 100644 index 0650011..0000000 --- a/lib/utils/genKey.js +++ /dev/null @@ -1,13 +0,0 @@ -var lastKey = 0; - -/* - Generate a random key - @return {String} -*/ -function generateKey() { - lastKey += 1; - var str = lastKey.toString(16); - return '00000'.slice(str.length) + str; -} - -module.exports = generateKey; diff --git a/lib/utils/git.js b/lib/utils/git.js deleted file mode 100644 index 6884b83..0000000 --- a/lib/utils/git.js +++ /dev/null @@ -1,133 +0,0 @@ -var is = require('is'); -var path = require('path'); -var crc = require('crc'); -var URI = require('urijs'); - -var pathUtil = require('./path'); -var Promise = require('./promise'); -var command = require('./command'); -var fs = require('./fs'); - -var GIT_PREFIX = 'git+'; - -function Git() { - this.tmpDir; - this.cloned = {}; -} - -// Return an unique ID for a combinaison host/ref -Git.prototype.repoID = function(host, ref) { - return crc.crc32(host+'#'+(ref || '')).toString(16); -}; - -// Allocate a temporary folder for cloning repos in it -Git.prototype.allocateDir = function() { - var that = this; - - if (this.tmpDir) return Promise(); - - return fs.tmpDir() - .then(function(dir) { - that.tmpDir = dir; - }); -}; - -// Clone a git repository if non existant -Git.prototype.clone = function(host, ref) { - var that = this; - - return this.allocateDir() - - // Return or clone the git repo - .then(function() { - // Unique ID for repo/ref combinaison - var repoId = that.repoID(host, ref); - - // Absolute path to the folder - var repoPath = path.join(that.tmpDir, repoId); - - if (that.cloned[repoId]) return repoPath; - - // Clone repo - return command.exec('git clone '+host+' '+repoPath) - - // Checkout reference if specified - .then(function() { - that.cloned[repoId] = true; - - if (!ref) return; - return command.exec('git checkout '+ref, { cwd: repoPath }); - }) - .thenResolve(repoPath); - }); -}; - -// Get file from a git repo -Git.prototype.resolve = function(giturl) { - // Path to a file in a git repo? - if (!Git.isUrl(giturl)) { - if (this.resolveRoot(giturl)) return Promise(giturl); - return Promise(null); - } - if (is.string(giturl)) giturl = Git.parseUrl(giturl); - if (!giturl) return Promise(null); - - // Clone or get from cache - return this.clone(giturl.host, giturl.ref) - .then(function(repo) { - return path.resolve(repo, giturl.filepath); - }); -}; - -// Return root of git repo from a filepath -Git.prototype.resolveRoot = function(filepath) { - var relativeToGit, repoId; - - // No git repo cloned, or file is not in a git repository - if (!this.tmpDir || !pathUtil.isInRoot(this.tmpDir, filepath)) return null; - - // Extract first directory (is the repo id) - relativeToGit = path.relative(this.tmpDir, filepath); - repoId = relativeToGit.split(path.sep)[0]; - if (!repoId) { - return; - } - - // Return an absolute file - return path.resolve(this.tmpDir, repoId); -}; - -// Check if an url is a git dependency url -Git.isUrl = function(giturl) { - return (giturl.indexOf(GIT_PREFIX) === 0); -}; - -// Parse and extract infos -Git.parseUrl = function(giturl) { - var ref, uri, fileParts, filepath; - - if (!Git.isUrl(giturl)) return null; - giturl = giturl.slice(GIT_PREFIX.length); - - uri = new URI(giturl); - ref = uri.fragment() || null; - uri.fragment(null); - - // Extract file inside the repo (after the .git) - fileParts = uri.path().split('.git'); - filepath = fileParts.length > 1? fileParts.slice(1).join('.git') : ''; - if (filepath[0] == '/') { - filepath = filepath.slice(1); - } - - // Recreate pathname without the real filename - uri.path(fileParts[0] + '.git'); - - return { - host: uri.toString(), - ref: ref, - filepath: filepath - }; -}; - -module.exports = Git; diff --git a/lib/utils/images.js b/lib/utils/images.js deleted file mode 100644 index 6d4b927..0000000 --- a/lib/utils/images.js +++ /dev/null @@ -1,60 +0,0 @@ -var Promise = require('./promise'); -var command = require('./command'); -var fs = require('./fs'); -var error = require('./error'); - -// Convert a svg file to a pmg -function convertSVGToPNG(source, dest, options) { - if (!fs.existsSync(source)) return Promise.reject(new error.FileNotFoundError({ filename: source })); - - return command.spawn('svgexport', [source, dest]) - .fail(function(err) { - if (err.code == 'ENOENT') { - err = error.RequireInstallError({ - cmd: 'svgexport', - install: 'Install it using: "npm install svgexport -g"' - }); - } - throw err; - }) - .then(function() { - if (fs.existsSync(dest)) return; - - throw new Error('Error converting '+source+' into '+dest); - }); -} - -// Convert a svg buffer to a png file -function convertSVGBufferToPNG(buf, dest) { - // Create a temporary SVG file to convert - return fs.tmpFile({ - postfix: '.svg' - }) - .then(function(tmpSvg) { - return fs.writeFile(tmpSvg, buf) - .then(function() { - return convertSVGToPNG(tmpSvg, dest); - }); - }); -} - -// Converts a inline data: to png file -function convertInlinePNG(source, dest) { - if (!/^data\:image\/png/.test(source)) return Promise.reject(new Error('Source is not a PNG data-uri')); - - var base64data = source.split('data:image/png;base64,')[1]; - var buf = new Buffer(base64data, 'base64'); - - return fs.writeFile(dest, buf) - .then(function() { - if (fs.existsSync(dest)) return; - - throw new Error('Error converting '+source+' into '+dest); - }); -} - -module.exports = { - convertSVGToPNG: convertSVGToPNG, - convertSVGBufferToPNG: convertSVGBufferToPNG, - convertInlinePNG: convertInlinePNG -};
\ No newline at end of file diff --git a/lib/utils/location.js b/lib/utils/location.js deleted file mode 100644 index 00d8004..0000000 --- a/lib/utils/location.js +++ /dev/null @@ -1,139 +0,0 @@ -var url = require('url'); -var path = require('path'); - -// Is the url an external url -function isExternal(href) { - try { - return Boolean(url.parse(href).protocol) && !isDataURI(href); - } catch(err) { - return false; - } -} - -// Is the url an iniline data-uri -function isDataURI(href) { - try { - return Boolean(url.parse(href).protocol) && (url.parse(href).protocol === 'data:'); - } catch(err) { - return false; - } -} - -// Inverse of isExternal -function isRelative(href) { - return !isExternal(href); -} - -// Return true if the link is an achor -function isAnchor(href) { - try { - var parsed = url.parse(href); - return !!(!parsed.protocol && !parsed.path && parsed.hash); - } catch(err) { - return false; - } -} - -// Normalize a path to be a link -function normalize(s) { - return path.normalize(s).replace(/\\/g, '/'); -} - -/** - * Flatten a path, it removes the leading "/" - * - * @param {String} href - * @return {String} - */ -function flatten(href) { - href = normalize(href); - if (href[0] == '/') { - href = normalize(href.slice(1)); - } - - return href; -} - -/** - * Convert a relative path to absolute - * - * @param {String} href - * @param {String} dir: directory parent of the file currently in rendering process - * @param {String} outdir: directory parent from the html output - * @return {String} - */ -function toAbsolute(_href, dir, outdir) { - if (isExternal(_href) || isDataURI(_href)) { - return _href; - } - - outdir = outdir == undefined? dir : outdir; - - _href = normalize(_href); - dir = normalize(dir); - outdir = normalize(outdir); - - // Path "_href" inside the base folder - var hrefInRoot = normalize(path.join(dir, _href)); - if (_href[0] == '/') { - hrefInRoot = normalize(_href.slice(1)); - } - - // Make it relative to output - _href = path.relative(outdir, hrefInRoot); - - // Normalize windows paths - _href = normalize(_href); - - return _href; -} - -/** - * Convert an absolute path to a relative path for a specific folder (dir) - * ('test/', 'hello.md') -> '../hello.md' - * - * @param {String} dir: current directory - * @param {String} file: absolute path of file - * @return {String} - */ -function relative(dir, file) { - var isDirectory = file.slice(-1) === '/'; - return normalize(path.relative(dir, file)) + (isDirectory? '/': ''); -} - -/** - * Convert an absolute path to a relative path for a specific folder (dir) - * ('test/test.md', 'hello.md') -> '../hello.md' - * - * @param {String} baseFile: current file - * @param {String} file: absolute path of file - * @return {String} - */ -function relativeForFile(baseFile, file) { - return relative(path.dirname(baseFile), file); -} - -/** - * Compare two paths, return true if they are identical - * ('README.md', './README.md') -> true - * - * @param {String} p1: first path - * @param {String} p2: second path - * @return {Boolean} - */ -function areIdenticalPaths(p1, p2) { - return normalize(p1) === normalize(p2); -} - -module.exports = { - areIdenticalPaths: areIdenticalPaths, - isDataURI: isDataURI, - isExternal: isExternal, - isRelative: isRelative, - isAnchor: isAnchor, - normalize: normalize, - toAbsolute: toAbsolute, - relative: relative, - relativeForFile: relativeForFile, - flatten: flatten -}; diff --git a/lib/utils/logger.js b/lib/utils/logger.js deleted file mode 100644 index 6fac92b..0000000 --- a/lib/utils/logger.js +++ /dev/null @@ -1,172 +0,0 @@ -var is = require('is'); -var util = require('util'); -var color = require('bash-color'); -var Immutable = require('immutable'); - -var LEVELS = Immutable.Map({ - DEBUG: 0, - INFO: 1, - WARN: 2, - ERROR: 3, - DISABLED: 10 -}); - -var COLORS = Immutable.Map({ - DEBUG: color.purple, - INFO: color.cyan, - WARN: color.yellow, - ERROR: color.red -}); - -function Logger(write, logLevel) { - if (!(this instanceof Logger)) return new Logger(write, logLevel); - - this._write = write || function(msg) { - if(process.stdout) { - process.stdout.write(msg); - } - }; - this.lastChar = '\n'; - - this.setLevel(logLevel || 'info'); - - // Create easy-to-use method like "logger.debug.ln('....')" - LEVELS.forEach(function(level, levelKey) { - if (levelKey === 'DISABLED') { - return; - } - levelKey = levelKey.toLowerCase(); - - this[levelKey] = this.log.bind(this, level); - this[levelKey].ln = this.logLn.bind(this, level); - this[levelKey].ok = this.ok.bind(this, level); - this[levelKey].fail = this.fail.bind(this, level); - this[levelKey].promise = this.promise.bind(this, level); - }, this); -} - -/** - Change minimum level - - @param {String} logLevel -*/ -Logger.prototype.setLevel = function(logLevel) { - if (is.string(logLevel)) { - logLevel = logLevel.toUpperCase(); - logLevel = LEVELS.get(logLevel); - } - - this.logLevel = logLevel; -}; - -/** - Return minimum logging level - - @return {Number} -*/ -Logger.prototype.getLevel = function(logLevel) { - return this.logLevel; -}; - -/** - Print a simple string - - @param {String} -*/ -Logger.prototype.write = function(msg) { - msg = msg.toString(); - this.lastChar = msg[msg.length - 1]; - return this._write(msg); -}; - -/** - Format a string using the first argument as a printf-like format. -*/ -Logger.prototype.format = function() { - return util.format.apply(util, arguments); -}; - -/** - Print a line - - @param {String} -*/ -Logger.prototype.writeLn = function(msg) { - return this.write((msg || '')+'\n'); -}; - -/** - Log/Print a message if level is allowed - - @param {Number} level -*/ -Logger.prototype.log = function(level) { - if (level < this.logLevel) return; - - var levelKey = LEVELS.findKey(function(v) { - return v === level; - }); - var args = Array.prototype.slice.apply(arguments, [1]); - var msg = this.format.apply(this, args); - - if (this.lastChar == '\n') { - msg = COLORS.get(levelKey)(levelKey.toLowerCase()+':')+' '+msg; - } - - return this.write(msg); -}; - -/** - Log/Print a line if level is allowed -*/ -Logger.prototype.logLn = function() { - if (this.lastChar != '\n') this.write('\n'); - - var args = Array.prototype.slice.apply(arguments); - args.push('\n'); - return this.log.apply(this, args); -}; - -/** - Log a confirmation [OK] -*/ -Logger.prototype.ok = function(level) { - var args = Array.prototype.slice.apply(arguments, [1]); - var msg = this.format.apply(this, args); - if (arguments.length > 1) { - this.logLn(level, color.green('>> ') + msg.trim().replace(/\n/g, color.green('\n>> '))); - } else { - this.log(level, color.green('OK'), '\n'); - } -}; - -/** - Log a "FAIL" -*/ -Logger.prototype.fail = function(level) { - return this.log(level, color.red('ERROR') + '\n'); -}; - -/** - Log state of a promise - - @param {Number} level - @param {Promise} - @return {Promise} -*/ -Logger.prototype.promise = function(level, p) { - var that = this; - - return p. - then(function(st) { - that.ok(level); - return st; - }, function(err) { - that.fail(level); - throw err; - }); -}; - -Logger.LEVELS = LEVELS; - -module.exports = Logger; diff --git a/lib/utils/mergeDefaults.js b/lib/utils/mergeDefaults.js deleted file mode 100644 index 47a374b..0000000 --- a/lib/utils/mergeDefaults.js +++ /dev/null @@ -1,16 +0,0 @@ -var Immutable = require('immutable'); - -/** - * Merge - * @param {Object|Map} obj - * @param {Object|Map} src - * @return {Object} - */ -function mergeDefaults(obj, src) { - var objValue = Immutable.fromJS(obj); - var srcValue = Immutable.fromJS(src); - - return srcValue.mergeDeep(objValue).toJS(); -} - -module.exports = mergeDefaults; diff --git a/lib/utils/path.js b/lib/utils/path.js deleted file mode 100644 index 26b6005..0000000 --- a/lib/utils/path.js +++ /dev/null @@ -1,74 +0,0 @@ -var path = require('path'); -var error = require('./error'); - -// Normalize a filename -function normalizePath(filename) { - return path.normalize(filename); -} - -// Return true if file path is inside a folder -function isInRoot(root, filename) { - root = path.normalize(root); - filename = path.normalize(filename); - - if (root === '.') { - return true; - } - if (root[root.length - 1] != path.sep) { - root = root + path.sep; - } - - return (filename.substr(0, root.length) === root); -} - -// Resolve paths in a specific folder -// Throw error if file is outside this folder -function resolveInRoot(root) { - var input, result; - var args = Array.prototype.slice.call(arguments, 1); - - input = args - .reduce(function(current, p) { - // Handle path relative to book root ("/README.md") - if (p[0] == '/' || p[0] == '\\') return p.slice(1); - - return current? path.join(current, p) : path.normalize(p); - }, ''); - - result = path.resolve(root, input); - - if (!isInRoot(root, result)) { - throw new error.FileOutOfScopeError({ - filename: result, - root: root - }); - } - - return result; -} - -// Chnage extension of a file -function setExtension(filename, ext) { - return path.join( - path.dirname(filename), - path.basename(filename, path.extname(filename)) + ext - ); -} - -/* - Return true if a filename is relative. - - @param {String} - @return {Boolean} -*/ -function isPureRelative(filename) { - return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0); -} - -module.exports = { - isInRoot: isInRoot, - resolveInRoot: resolveInRoot, - normalize: normalizePath, - setExtension: setExtension, - isPureRelative: isPureRelative -}; diff --git a/lib/utils/promise.js b/lib/utils/promise.js deleted file mode 100644 index b5cca4b..0000000 --- a/lib/utils/promise.js +++ /dev/null @@ -1,148 +0,0 @@ -var Q = require('q'); -var Immutable = require('immutable'); - -// Debugging for long stack traces -if (process.env.DEBUG || process.env.CI) { - Q.longStackSupport = true; -} - -/** - * Reduce an array to a promise - * - * @param {Array|List} arr - * @param {Function(value, element, index)} - * @return {Promise<Mixed>} - */ -function reduce(arr, iter, base) { - arr = Immutable.Iterable.isIterable(arr)? arr : Immutable.List(arr); - - return arr.reduce(function(prev, elem, key) { - return prev - .then(function(val) { - return iter(val, elem, key); - }); - }, Q(base)); -} - -/** - * Iterate over an array using an async iter - * - * @param {Array|List} arr - * @param {Function(value, element, index)} - * @return {Promise} - */ -function forEach(arr, iter) { - return reduce(arr, function(val, el, key) { - return iter(el, key); - }); -} - -/** - * Transform an array - * - * @param {Array|List} arr - * @param {Function(value, element, index)} - * @return {Promise} - */ -function serie(arr, iter, base) { - return reduce(arr, function(before, item, key) { - return Q(iter(item, key)) - .then(function(r) { - before.push(r); - return before; - }); - }, []); -} - -/** - * Iter over an array and return first result (not null) - * - * @param {Array|List} arr - * @param {Function(element, index)} - * @return {Promise<Mixed>} - */ -function some(arr, iter) { - arr = Immutable.List(arr); - - return arr.reduce(function(prev, elem, i) { - return prev.then(function(val) { - if (val) return val; - - return iter(elem, i); - }); - }, Q()); -} - -/** - * Map an array using an async (promised) iterator - * - * @param {Array|List} arr - * @param {Function(element, index)} - * @return {Promise<List>} - */ -function mapAsList(arr, iter) { - return reduce(arr, function(prev, entry, i) { - return Q(iter(entry, i)) - .then(function(out) { - prev.push(out); - return prev; - }); - }, []); -} - -/** - * Map an array or map - * - * @param {Array|List|Map|OrderedMap} arr - * @param {Function(element, key)} - * @return {Promise<List|Map|OrderedMap>} - */ -function map(arr, iter) { - if (Immutable.Map.isMap(arr)) { - var type = 'Map'; - if (Immutable.OrderedMap.isOrderedMap(arr)) { - type = 'OrderedMap'; - } - - return mapAsList(arr, function(value, key) { - return Q(iter(value, key)) - .then(function(result) { - return [key, result]; - }); - }) - .then(function(result) { - return Immutable[type](result); - }); - } else { - return mapAsList(arr, iter) - .then(function(result) { - return Immutable.List(result); - }); - } -} - - -/** - * Wrap a function in a promise - * - * @param {Function} func - * @return {Funciton} - */ -function wrap(func) { - return function() { - var args = Array.prototype.slice.call(arguments, 0); - - return Q() - .then(function() { - return func.apply(null, args); - }); - }; -} - -module.exports = Q; -module.exports.forEach = forEach; -module.exports.reduce = reduce; -module.exports.map = map; -module.exports.serie = serie; -module.exports.some = some; -module.exports.wrapfn = wrap; diff --git a/lib/utils/reducedObject.js b/lib/utils/reducedObject.js deleted file mode 100644 index 7bcfd5b..0000000 --- a/lib/utils/reducedObject.js +++ /dev/null @@ -1,33 +0,0 @@ -var Immutable = require('immutable'); - -/** - * Reduce the difference between a map and its default version - * @param {Map} defaultVersion - * @param {Map} currentVersion - * @return {Map} The properties of currentVersion that differs from defaultVersion - */ -function reducedObject(defaultVersion, currentVersion) { - if(defaultVersion === undefined) { - return currentVersion; - } - - return currentVersion.reduce(function(result, value, key) { - var defaultValue = defaultVersion.get(key); - - if (Immutable.Map.isMap(value)) { - var diffs = reducedObject(defaultValue, value); - - if (diffs.size > 0) { - return result.set(key, diffs); - } - } - - if (Immutable.is(defaultValue, value)) { - return result; - } - - return result.set(key, value); - }, Immutable.Map()); -} - -module.exports = reducedObject; diff --git a/lib/utils/timing.js b/lib/utils/timing.js deleted file mode 100644 index e6b0323..0000000 --- a/lib/utils/timing.js +++ /dev/null @@ -1,97 +0,0 @@ -var Immutable = require('immutable'); -var is = require('is'); - -var timers = {}; -var startDate = Date.now(); - -/** - Mesure an operation - - @parqm {String} type - @param {Promise} p - @return {Promise} -*/ -function measure(type, p) { - timers[type] = timers[type] || { - type: type, - count: 0, - total: 0, - min: undefined, - max: 0 - }; - - var start = Date.now(); - - return p - .fin(function() { - var end = Date.now(); - var duration = (end - start); - - timers[type].count ++; - timers[type].total += duration; - - if (is.undefined(timers[type].min)) { - timers[type].min = duration; - } else { - timers[type].min = Math.min(timers[type].min, duration); - } - - timers[type].max = Math.max(timers[type].max, duration); - }); -} - -/** - Return a milliseconds number as a second string - - @param {Number} ms - @return {String} -*/ -function time(ms) { - if (ms < 1000) { - return (ms.toFixed(0)) + 'ms'; - } - - return (ms/1000).toFixed(2) + 's'; -} - -/** - Dump all timers to a logger - - @param {Logger} logger -*/ -function dump(logger) { - var prefix = ' > '; - var measured = 0; - var totalDuration = Date.now() - startDate; - - // Enable debug logging - var logLevel = logger.getLevel(); - logger.setLevel('debug'); - - Immutable.Map(timers) - .valueSeq() - .sortBy(function(timer) { - measured += timer.total; - return timer.total; - }) - .forEach(function(timer) { - var percent = (timer.total * 100) / totalDuration; - - - logger.debug.ln((percent.toFixed(1)) + '% of time spent in "' + timer.type + '" (' + timer.count + ' times) :'); - logger.debug.ln(prefix + 'Total: ' + time(timer.total)+ ' | Average: ' + time(timer.total / timer.count)); - logger.debug.ln(prefix + 'Min: ' + time(timer.min) + ' | Max: ' + time(timer.max)); - logger.debug.ln('---------------------------'); - }); - - - logger.debug.ln(time(totalDuration - measured) + ' spent in non-mesured sections'); - - // Rollback to previous level - logger.setLevel(logLevel); -} - -module.exports = { - measure: measure, - dump: dump -}; |