Initial commit
[yaffs-website] / node_modules / gulp / node_modules / vinyl / index.js
1 var path = require('path');
2 var clone = require('clone');
3 var cloneStats = require('clone-stats');
4 var cloneBuffer = require('./lib/cloneBuffer');
5 var isBuffer = require('./lib/isBuffer');
6 var isStream = require('./lib/isStream');
7 var isNull = require('./lib/isNull');
8 var inspectStream = require('./lib/inspectStream');
9 var Stream = require('stream');
10
11 function File(file) {
12   if (!file) file = {};
13
14   // record path change
15   var history = file.path ? [file.path] : file.history;
16   this.history = history || [];
17
18   // TODO: should this be moved to vinyl-fs?
19   this.cwd = file.cwd || process.cwd();
20   this.base = file.base || this.cwd;
21
22   // stat = fs stats object
23   // TODO: should this be moved to vinyl-fs?
24   this.stat = file.stat || null;
25
26   // contents = stream, buffer, or null if not read
27   this.contents = file.contents || null;
28 }
29
30 File.prototype.isBuffer = function() {
31   return isBuffer(this.contents);
32 };
33
34 File.prototype.isStream = function() {
35   return isStream(this.contents);
36 };
37
38 File.prototype.isNull = function() {
39   return isNull(this.contents);
40 };
41
42 // TODO: should this be moved to vinyl-fs?
43 File.prototype.isDirectory = function() {
44   return this.isNull() && this.stat && this.stat.isDirectory();
45 };
46
47 File.prototype.clone = function(opt) {
48   if (typeof opt === 'boolean') {
49     opt = {
50       deep: opt,
51       contents: true
52     };
53   } else if (!opt) {
54     opt = {
55       deep: false,
56       contents: true
57     };
58   } else {
59     opt.deep = opt.deep === true;
60     opt.contents = opt.contents !== false;
61   }
62
63   // clone our file contents
64   var contents;
65   if (this.isStream()) {
66     contents = this.contents.pipe(new Stream.PassThrough());
67     this.contents = this.contents.pipe(new Stream.PassThrough());
68   } else if (this.isBuffer()) {
69     contents = opt.contents ? cloneBuffer(this.contents) : this.contents;
70   }
71
72   var file = new File({
73     cwd: this.cwd,
74     base: this.base,
75     stat: (this.stat ? cloneStats(this.stat) : null),
76     history: this.history.slice(),
77     contents: contents
78   });
79
80   // clone our custom properties
81   Object.keys(this).forEach(function(key) {
82     // ignore built-in fields
83     if (key === '_contents' || key === 'stat' ||
84       key === 'history' || key === 'path' ||
85       key === 'base' || key === 'cwd') {
86       return;
87     }
88     file[key] = opt.deep ? clone(this[key], true) : this[key];
89   }, this);
90   return file;
91 };
92
93 File.prototype.pipe = function(stream, opt) {
94   if (!opt) opt = {};
95   if (typeof opt.end === 'undefined') opt.end = true;
96
97   if (this.isStream()) {
98     return this.contents.pipe(stream, opt);
99   }
100   if (this.isBuffer()) {
101     if (opt.end) {
102       stream.end(this.contents);
103     } else {
104       stream.write(this.contents);
105     }
106     return stream;
107   }
108
109   // isNull
110   if (opt.end) stream.end();
111   return stream;
112 };
113
114 File.prototype.inspect = function() {
115   var inspect = [];
116
117   // use relative path if possible
118   var filePath = (this.base && this.path) ? this.relative : this.path;
119
120   if (filePath) {
121     inspect.push('"'+filePath+'"');
122   }
123
124   if (this.isBuffer()) {
125     inspect.push(this.contents.inspect());
126   }
127
128   if (this.isStream()) {
129     inspect.push(inspectStream(this.contents));
130   }
131
132   return '<File '+inspect.join(' ')+'>';
133 };
134
135 // virtual attributes
136 // or stuff with extra logic
137 Object.defineProperty(File.prototype, 'contents', {
138   get: function() {
139     return this._contents;
140   },
141   set: function(val) {
142     if (!isBuffer(val) && !isStream(val) && !isNull(val)) {
143       throw new Error('File.contents can only be a Buffer, a Stream, or null.');
144     }
145     this._contents = val;
146   }
147 });
148
149 // TODO: should this be moved to vinyl-fs?
150 Object.defineProperty(File.prototype, 'relative', {
151   get: function() {
152     if (!this.base) throw new Error('No base specified! Can not get relative.');
153     if (!this.path) throw new Error('No path specified! Can not get relative.');
154     return path.relative(this.base, this.path);
155   },
156   set: function() {
157     throw new Error('File.relative is generated from the base and path attributes. Do not modify it.');
158   }
159 });
160
161 Object.defineProperty(File.prototype, 'path', {
162   get: function() {
163     return this.history[this.history.length - 1];
164   },
165   set: function(path) {
166     if (typeof path !== 'string') throw new Error('path should be string');
167
168     // record history only when path changed
169     if (path && path !== this.path) {
170       this.history.push(path);
171     }
172   }
173 });
174
175 module.exports = File;