Skip to content

Commit

Permalink
New: Allow custom properties to be assigned in constructor (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
darsain authored and phated committed Sep 27, 2016
1 parent 5dbe19c commit 0f3a8a9
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 8 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ File.isVinyl(dummy); // true
File.isVinyl(notAFile); // false
```

### isCustomProp
Vinyl checks if a property is not managed internally, such as `sourceMap`. This is than used in `constructor(options)` when setting, and `clone()` when copying properties.

```js
var File = require('vinyl');

File.isCustomProp('sourceMap'); // true
File.isCustomProp('path'); // false -> internal getter/setter
```

Read more in [Extending Vinyl](#extending-vinyl).

### constructor(options)
#### options.cwd
Type: `String`<br><br>Default: `process.cwd()`
Expand Down Expand Up @@ -61,6 +73,16 @@ File contents.

Type: `Buffer, Stream, or null`<br><br>Default: `null`

#### options.{custom}
Any other option properties will just be assigned to the new File object.

```js
var File = require('vinyl');

var file = new File({foo: 'bar'});
file.foo === 'bar'; // true
```

### isBuffer()
Returns true if file.contents is a Buffer.

Expand Down Expand Up @@ -203,6 +225,36 @@ console.log(file.extname); // .js
console.log(file.path); // /test/file.js
```

## Extending Vinyl
When extending Vinyl into your own class with extra features, you need to think about a few things.

When you have your own properties that are managed internally, you need to extend the static `isCustomProp` method to return `false` when one of these properties is queried.

```js
const File = require('vinyl');

const builtInProps = ['foo', '_foo'];

class SuperFile extends File {
constructor(options) {
super(options);
this._foo = 'example internal read-only value';
}

get foo() {
return this._foo;
}

static isCustomProp(name) {
return super.isCustomProp(name) && builtInProps.indexOf(name) === -1;
}
}
```

This makes properties `foo` and `_foo` ignored when cloning, and when passed in options to `constructor(options)` so they don't get assigned to the new object.

Same goes for `clone()`. If you have your own internal stuff that needs special handling during cloning, you should extend it to do so.

[npm-url]: https://npmjs.org/package/vinyl
[npm-image]: https://badge.fury.io/js/vinyl.svg
[travis-url]: https://travis-ci.org/gulpjs/vinyl
Expand Down
31 changes: 23 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ var inspectStream = require('./lib/inspectStream');
var Stream = require('stream');
var replaceExt = require('replace-ext');

var builtInFields = [
'_contents', 'contents', 'stat', 'history', 'path', 'base', 'cwd',
];

function File(file) {
var self = this;

if (!file) {
file = {};
}
Expand All @@ -28,6 +34,13 @@ function File(file) {
this.contents = file.contents || null;

this._isVinyl = true;

// Set custom properties
Object.keys(file).forEach(function(key) {
if (self.constructor.isCustomProp(key)) {
self[key] = file[key];
}
});
}

File.prototype.isBuffer = function() {
Expand All @@ -48,6 +61,8 @@ File.prototype.isDirectory = function() {
};

File.prototype.clone = function(opt) {
var self = this;

if (typeof opt === 'boolean') {
opt = {
deep: opt,
Expand Down Expand Up @@ -82,14 +97,10 @@ File.prototype.clone = function(opt) {

// Clone our custom properties
Object.keys(this).forEach(function(key) {
// Ignore built-in fields
if (key === '_contents' || key === 'stat' ||
key === 'history' || key === 'path' ||
key === 'base' || key === 'cwd') {
return;
}
file[key] = opt.deep ? clone(this[key], true) : this[key];
}, this);
if (self.constructor.isCustomProp(key)) {
file[key] = opt.deep ? clone(self[key], true) : self[key];
}
});
return file;
};

Expand Down Expand Up @@ -141,6 +152,10 @@ File.prototype.inspect = function() {
return '<File ' + inspect.join(' ') + '>';
};

File.isCustomProp = function(key) {
return builtInFields.indexOf(key) === -1;
};

File.isVinyl = function(file) {
return (file && file._isVinyl === true) || false;
};
Expand Down
7 changes: 7 additions & 0 deletions test/File.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ describe('File', function() {
file.contents.should.equal(val);
done();
});

it('should set custom properties', function(done) {
var sourceMap = {};
var file = new File({ sourceMap: sourceMap });
file.sourceMap.should.equal(sourceMap);
done();
});
});

describe('isBuffer()', function() {
Expand Down

0 comments on commit 0f3a8a9

Please sign in to comment.