Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for configurable file extensions #163

Merged
merged 1 commit into from
Feb 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,23 @@ of the pre-transpiled code. You'll have to configure your custom require hook
to inline the source map in the transpiled code. For Babel that means setting
the `sourceMaps` option to `inline`.

## Support For Custom File Extensions (.jsx, .es6)
Supporting file extensions can be configured through either the configuration arguments or with the `nyc` config section in `package.json`.

```shell
nyc --extension .jsx --extension .es6 npm test
```

```json
{"nyc": {
"extensions": [
".jsx",
".es6"
]
}
}
```

## Checking Coverage

nyc exposes istanbul's check-coverage tool. After running your tests with nyc,
Expand Down
9 changes: 9 additions & 0 deletions bin/nyc.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ var yargs = require('yargs')
type: 'boolean',
describe: 'cache instrumentation results for improved performance'
})
.options('e', {
alias: 'extension',
default: [],
describe: 'a list of extensions that nyc should handle in addition to .js'
})
.option('check-coverage', {
type: 'boolean',
default: false,
Expand Down Expand Up @@ -128,6 +133,7 @@ if (argv._[0] === 'report') {
} else if (argv._.length) {
// wrap subprocesses and execute argv[1]
if (!Array.isArray(argv.require)) argv.require = [argv.require]
if (!Array.isArray(argv.extension)) argv.extension = [argv.extension]

var nyc = (new NYC({
require: argv.require
Expand All @@ -143,6 +149,9 @@ if (argv._[0] === 'report') {
if (argv.require.length) {
env.NYC_REQUIRE = argv.require.join(',')
}
if (argv.extension.length) {
env.NYC_EXTENSION = argv.extension.join(',')
}
sw([wrapper], env)

foreground(nyc.mungeArgs(argv), function (done) {
Expand Down
1 change: 1 addition & 0 deletions bin/wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ try {

;(new NYC({
require: process.env.NYC_REQUIRE ? process.env.NYC_REQUIRE.split(',') : [],
extension: process.env.NYC_EXTENSION ? process.env.NYC_EXTENSION.split(',') : [],
enableCache: process.env.NYC_CACHE === 'enable'
})).wrap()

Expand Down
38 changes: 30 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var md5hex = require('md5-hex')
var findCacheDir = require('find-cache-dir')
var pkgUp = require('pkg-up')
var readPkg = require('read-pkg')
var js = require('default-require-extensions/js')

/* istanbul ignore next */
if (/index\.covered\.js$/.test(__filename)) {
Expand Down Expand Up @@ -53,7 +54,14 @@ function NYC (opts) {
// require extensions can be provided as config in package.json.
this.require = arrify(config.require || opts.require)

this.transform = this._createTransform()
this.extensions = arrify(config.extension || opts.extension).concat('.js').map(function (ext) {
return ext.toLowerCase()
})

this.transforms = this.extensions.reduce(function (transforms, ext) {
transforms[ext] = this._createTransform(ext)
return transforms
}.bind(this), {})

this.sourceMapCache = new SourceMapCache()

Expand All @@ -79,7 +87,7 @@ NYC.prototype._loadConfig = function (opts) {
return config
}

NYC.prototype._createTransform = function () {
NYC.prototype._createTransform = function (ext) {
var _this = this
return cachingTransform({
salt: JSON.stringify({
Expand All @@ -94,7 +102,7 @@ NYC.prototype._createTransform = function () {
factory: this._transformFactory.bind(this),
cacheDir: this.cacheDirectory,
disableCache: !this.enableCache,
ext: '.js'
ext: ext
})
}

Expand Down Expand Up @@ -212,7 +220,15 @@ NYC.prototype._maybeInstrumentSource = function (code, filename, relFile) {
return null
}

return this.transform(code, {filename: filename, relFile: relFile})
var ext, transform
for (ext in this.transforms) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking you could iterate over this.extensions here, though we're veering quite far into premature optimization land.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree - it's more concise in the code to just use for...in. And in most cases I would think we would have 2 or 3 extensions to iterate through at the most. Yes it could be many files, but still I think it has to get into the 100s of thousands before any noticeable difference between for..in and for.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not making a ext => transform object/Map?

if (filename.toLowerCase().substr(-ext.length) === ext) {
transform = this.transforms[ext]
break
}
}

return transform ? transform(code, {filename: filename, relFile: relFile}) : null
}

NYC.prototype._transformFactory = function (cacheDir) {
Expand All @@ -238,11 +254,17 @@ NYC.prototype._transformFactory = function (cacheDir) {
}
}

NYC.prototype._handleJs = function (code, filename) {
var relFile = path.relative(this.cwd, filename)
return this._maybeInstrumentSource(code, filename, relFile) || code
}

NYC.prototype._wrapRequire = function () {
var _this = this
appendTransform(function (code, filename) {
var relFile = path.relative(_this.cwd, filename)
return _this._maybeInstrumentSource(code, filename, relFile) || code
var handleJs = this._handleJs.bind(this)

this.extensions.forEach(function (ext) {
require.extensions[ext] = js
appendTransform(handleJs, ext)
})
}

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"test/source-map-cache.js",
"index.covered.js",
"test/fixtures/_generateCoverage.js"
]
],
"extension": [".es6"]
},
"standard": {
"ignore": [
Expand Down Expand Up @@ -65,6 +66,7 @@
"arrify": "^1.0.1",
"caching-transform": "^1.0.0",
"convert-source-map": "^1.1.2",
"default-require-extensions": "^1.0.0",
"find-cache-dir": "^0.1.1",
"foreground-child": "^1.3.5",
"glob": "^6.0.2",
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/check-instrumented.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function probe () {}

// When instrumented there will be references to variables like
// __cov_pwkoI2PYHp3LJXkn_erl1Q in the probe() source.
module.exports = function () {
return /\b__cov_\B/.test(probe + '')
}
7 changes: 7 additions & 0 deletions test/fixtures/check-instrumented.foo.bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function probe () {}

// When instrumented there will be references to variables like
// __cov_pwkoI2PYHp3LJXkn_erl1Q in the probe() source.
module.exports = function () {
return /\b__cov_\B/.test(probe + '')
}
3 changes: 2 additions & 1 deletion test/fixtures/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"exclude": [
"**/blarg",
"**/blerg"
]
],
"extension": [".es6", ".foo.BAR"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until it is easier to use opts over package.json config, I mixed the casing here a bit to test case-insensitive extension matching.

}
}
}
52 changes: 52 additions & 0 deletions test/src/nyc-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ describe('nyc', function () {

nyc.exclude.length.should.eql(19)
})

it("loads 'extension' patterns from package.json#config.nyc", function () {
var nyc = new NYC({
cwd: path.resolve(__dirname, '../fixtures')
})

nyc.extensions.length.should.eql(3)
})

it("loads 'extension' from package.json#nyc", function () {
var nyc = new NYC({
cwd: path.resolve(__dirname, '../..')
})

nyc.extensions.length.should.eql(2)
})
})

describe('_prepGlobPatterns', function () {
Expand Down Expand Up @@ -232,6 +248,42 @@ describe('nyc', function () {
})
})

describe('compile handlers for custom extensions are assigned', function () {
it('assigns a function to custom extensions', function () {
var nyc = new NYC({
cwd: path.resolve(__dirname, '../fixtures')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the cwd to use the fixtures package.json for these two tests, so that the looping can be tested as well as the case-insensitive matching in the next one.

})
nyc.reset()
nyc.wrap()

require.extensions['.es6'].should.be.a.function
require.extensions['.foo.bar'].should.be.a.function

// default should still exist
require.extensions['.js'].should.be.a.function
})

it('calls the `_handleJs` function for custom file extensions', function () {
// the `require` call to istanbul is deferred, loaded here so it doesn't mess with the hooks callCount
require('istanbul')

var nyc = new NYC({
cwd: path.resolve(__dirname, '../fixtures')
})

sinon.spy(nyc, '_handleJs')

nyc.reset()
nyc.wrap()

var check1 = require('../fixtures/check-instrumented.es6')
var check2 = require('../fixtures/check-instrumented.foo.bar')
check1().should.be.true
check2().should.be.true
nyc._handleJs.callCount.should.equal(2)
})
})

function testSignal (signal, done) {
var nyc = (new NYC({
cwd: fixtures
Expand Down