makestatic-core
Version:
Generic file processing library
264 lines (234 loc) • 5.77 kB
JavaScript
const File = require('makestatic-filewrap')
/**
* Encapsulates the output file lists.
*
* The `files` list is an array of file objects whilst
* the `assets` list is a map of relative file paths to file objects.
*
* @class FileList
*/
class FileList {
/**
* Create a FileList.
*
* @constructor FileList
* @param {Object} context the processing context.
* @param {Array} sources list of file names.
*/
constructor (context, sources = []) {
this._context = context
this._assets = {}
this.propagate(sources)
}
/**
* The processing context.
*
* @property {Object} context
* @readonly
*/
get context () {
return this._context
}
/**
* The root directory for input files.
*
* @property {String} root
* @readonly
*/
get root () {
return this._context.options.root
}
/**
* Raw list of input file names.
*
* @property {Array} sources
* @readonly
*/
get sources () {
return this._sources
}
/**
* List of current output files.
*
* @property {Array} files
* @readonly
*/
get files () {
return this._files
}
/**
* Map of current output files.
*
* @property {Object} assets list of output assets.
*/
get assets () {
return this._assets
}
set assets (val) {
this._assets = val
if (val) {
this._files = []
for (let k in val) {
this._files.push(val[k])
}
}
}
/**
* Add a file to the list by name or pointer.
*
* The file is not added if it already exists in the `files` list.
*
* @function add
* @member FileList
* @param {String|Object} options source file name or file properties.
*
* @returns the file on success otherwise undefined.
*/
add (options) {
const file = this.getFile(options)
const key = file.path
const index = this._files.findIndex((file) => {
return file.path === key
})
if (index === -1) {
this._assets[key] = file
this._files.push(file)
}
return index === -1 ? file : undefined
}
/**
* Remove a file from the list by name or pointer.
*
* @function remove
* @member FileList
* @param {String|Object} options source file name or file properties.
*
* @returns the file on success otherwise undefined.
*/
remove (options) {
const file = this.getFile(options)
const key = file.path
if (!this._assets[key]) {
throw new Error(`cannot remove non-existent file ${file.path}`)
}
delete this._assets[key]
const index = this._files.findIndex((file) => {
return file.path === key
})
if (index > -1) {
this._files.splice(index, 1)
}
return index > -1 ? file : undefined
}
/**
* Rewrite the output path for an existing file.
*
* @function rewrite
* @member FileList
* @param {String|Object} options source file name or file properties.
* @param {String} dest the new output path for the file.
*
* @throw Error if the file does not exist.
*
* @returns the file on success otherwise undefined.
*/
rewrite (options, dest) {
const file = this.get(options)
if (!file) {
throw new Error(`cannot rewrite non-existent file`)
}
this.remove(file)
file.output = dest
this.add(file)
return file
}
/**
* Rename the output file name for an existing file.
*
* @function rename
* @member FileList
* @param {String|Object} options source file name or file properties.
* @param {String} name the new output name for the file.
*
* @throw Error if the file does not exist.
*
* @returns the file on success otherwise undefined.
*/
rename (options, name) {
const file = this.get(options)
if (!file) {
throw new Error(`cannot rename non-existent file`)
}
const path = require('path')
const dest = path.join(
file.output ? path.dirname(file.output) : this.dir || '', name)
return this.rewrite(file, dest)
}
/**
* Get a file from the list by name or pointer.
*
* @function get
* @member FileList
* @param {String|Object} options source file name or file properties.
*
* @returns a file object or undefined.
*/
get (options) {
let key
if (typeof options === 'string') {
key = options
} else {
key = this.getFile(options).path
}
return this._assets[key]
}
/**
* Get a File pointer.
*
* Accepts an input file path which becomes the file `name` or a map of
* properties for the new file.
*
* If a `File` is passed it is returned.
*
* @function getFile
* @member FileList
* @param {String|Object} options source file name or file properties.
*
* @returns a file object.
*/
getFile (options) {
if (options instanceof File) {
return options
} else if (typeof options === 'string') {
options = {name: options}
}
if (!options.root) {
options.root = this.root
}
if (!options.dir) {
options.dir = this.context.options.output
}
// assume object file options
return new File(options)
}
/**
* Propagates the file lists converting file path strings to
* complex `filewrap` objects.
*
* @function propagate
* @member FileList
*
* @param {Array} sources list of input file names.
*/
propagate (sources) {
this._sources = sources.slice()
// set up linked list
this._files = this._sources.map((name) => {
const file = new File(
{name: name, root: this.root, dir: this.context.options.output})
this._assets[file.path] = file
return file
})
}
}
module.exports = FileList