'use strict' var p = require('./minpath') var proc = require('./minproc') var buffer = require('is-buffer') module.exports = VFile var own = {}.hasOwnProperty // Order of setting (least specific to most), we need this because otherwise // `{stem: 'a', path: '~/b.js'}` would throw, as a path is needed before a // stem can be set. var order = ['history', 'path', 'basename', 'stem', 'extname', 'dirname'] VFile.prototype.toString = toString // Access full path (`~/index.min.js`). Object.defineProperty(VFile.prototype, 'path', {get: getPath, set: setPath}) // Access parent path (`~`). Object.defineProperty(VFile.prototype, 'dirname', { get: getDirname, set: setDirname }) // Access basename (`index.min.js`). Object.defineProperty(VFile.prototype, 'basename', { get: getBasename, set: setBasename }) // Access extname (`.js`). Object.defineProperty(VFile.prototype, 'extname', { get: getExtname, set: setExtname }) // Access stem (`index.min`). Object.defineProperty(VFile.prototype, 'stem', {get: getStem, set: setStem}) // Construct a new file. function VFile(options) { var prop var index if (!options) { options = {} } else if (typeof options === 'string' || buffer(options)) { options = {contents: options} } else if ('message' in options && 'messages' in options) { return options } if (!(this instanceof VFile)) { return new VFile(options) } this.data = {} this.messages = [] this.history = [] this.cwd = proc.cwd() // Set path related properties in the correct order. index = -1 while (++index < order.length) { prop = order[index] if (own.call(options, prop)) { this[prop] = options[prop] } } // Set non-path related properties. for (prop in options) { if (order.indexOf(prop) < 0) { this[prop] = options[prop] } } } function getPath() { return this.history[this.history.length - 1] } function setPath(path) { assertNonEmpty(path, 'path') if (this.path !== path) { this.history.push(path) } } function getDirname() { return typeof this.path === 'string' ? p.dirname(this.path) : undefined } function setDirname(dirname) { assertPath(this.path, 'dirname') this.path = p.join(dirname || '', this.basename) } function getBasename() { return typeof this.path === 'string' ? p.basename(this.path) : undefined } function setBasename(basename) { assertNonEmpty(basename, 'basename') assertPart(basename, 'basename') this.path = p.join(this.dirname || '', basename) } function getExtname() { return typeof this.path === 'string' ? p.extname(this.path) : undefined } function setExtname(extname) { assertPart(extname, 'extname') assertPath(this.path, 'extname') if (extname) { if (extname.charCodeAt(0) !== 46 /* `.` */) { throw new Error('`extname` must start with `.`') } if (extname.indexOf('.', 1) > -1) { throw new Error('`extname` cannot contain multiple dots') } } this.path = p.join(this.dirname, this.stem + (extname || '')) } function getStem() { return typeof this.path === 'string' ? p.basename(this.path, this.extname) : undefined } function setStem(stem) { assertNonEmpty(stem, 'stem') assertPart(stem, 'stem') this.path = p.join(this.dirname || '', stem + (this.extname || '')) } // Get the value of the file. function toString(encoding) { return (this.contents || '').toString(encoding) } // Assert that `part` is not a path (i.e., does not contain `p.sep`). function assertPart(part, name) { if (part && part.indexOf(p.sep) > -1) { throw new Error( '`' + name + '` cannot be a path: did not expect `' + p.sep + '`' ) } } // Assert that `part` is not empty. function assertNonEmpty(part, name) { if (!part) { throw new Error('`' + name + '` cannot be empty') } } // Assert `path` exists. function assertPath(path, name) { if (!path) { throw new Error('Setting `' + name + '` requires `path` to be set too') } }