Skip to content
This repository has been archived by the owner on Nov 28, 2017. It is now read-only.

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jamestalmage committed Nov 15, 2015
0 parents commit d2b166b
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
@@ -0,0 +1,15 @@
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{package.json,*.yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .gitattributes
@@ -0,0 +1 @@
* text=auto
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
node_modules
coverage
.nyc_output
5 changes: 5 additions & 0 deletions .travis.yml
@@ -0,0 +1,5 @@
language: node_js
node_js:
- 'stable'
- '0.12'
- '0.10'
79 changes: 79 additions & 0 deletions index.js
@@ -0,0 +1,79 @@
'use strict';
module.exports = detective;
module.exports.metadata = extractMetadataFromResult;

function detective() {
return {
visitor: {
ImportDeclaration: visitImportDeclaration,
CallExpression: visitCallExpression
}
};
}

function visitImportDeclaration(path, state) {
if (includeImports(state)) {
addString(state, path.node.source.value);
}
}

function visitCallExpression(path, state) {
if (!includeRequire(state)) {
return;
}
var callee = path.get('callee');
if (callee.isIdentifier() && callee.node.name === word(state)) {
var arg = path.get('arguments.0');
if (arg && (!arg.isGenerated() || includeGenerated(state))) {
if (arg.isLiteral()) {
addString(state, arg.node.value);
} else {
var loc = addExpression(state, arg.node);
if (attachExpressionSource(state)) {
loc.code = state.file.code.slice(loc.start, loc.end);
}
}
}
}
}

function extractMetadataFromResult(result) {
return result.metadata.requires;
}

function requireMetadata(state) {
var metadata = state.file.metadata;
return metadata.requires || (metadata.requires = {strings: [], expressions: []});
}

function addExpression(state, node) {
var loc = {start: node.start, end: node.end};
requireMetadata(state).expressions.push(loc);
return loc;
}

function addString(state, string) {
requireMetadata(state).strings.push(string);
}

// OPTION EXTRACTION:

function word(state) {
return state.opts.word || 'require';
}

function includeGenerated(state) {
return Boolean(state.opts.includeGenerated);
}

function includeImports(state) {
return state.opts.includeImport !== false;
}

function includeRequire(state) {
return state.opts.includeRequire !== false;
}

function attachExpressionSource(state) {
return Boolean(state.opts.attachExpressionSource);
}
21 changes: 21 additions & 0 deletions license
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) James Talmage <james@talmage.io> (github.com/jamestalmage)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
38 changes: 38 additions & 0 deletions package.json
@@ -0,0 +1,38 @@
{
"name": "babel-plugin-detective",
"version": "0.0.0",
"description": "A Babel 6 plugin that scans the AST for require calls and import statements",
"license": "MIT",
"repository": "jamestalmage/babel-plugin-detective",
"author": {
"name": "James Talmage",
"email": "james@talmage.io",
"url": "github.com/jamestalmage"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "xo && nyc mocha"
},
"files": [
"index.js"
],
"keywords": [
"babel-plugin",
"detective",
"require",
"import",
"dependencies",
"scan",
"traverse"
],
"devDependencies": {
"babel-core": "^6.1.21",
"babel-preset-es2015": "^6.1.18",
"babel-preset-stage-3": "^6.1.18",
"babylon": "^6.1.21",
"mocha": "^2.3.3",
"nyc": "^3.2.2"
}
}
105 changes: 105 additions & 0 deletions readme.md
@@ -0,0 +1,105 @@
# babel-detective [![Build Status](https://travis-ci.org/jamestalmage/babel-plugin-detective.svg?branch=master)](https://travis-ci.org/jamestalmage/babel-plugin-detective)

> A Babel 6 plugin that scans the AST for require calls and import statements

## Install

```
$ npm install --save babel-plugin-detective babel-core
```

## Usage

```js
import babel from 'babel-core';
const detective = require('babel-plugin-detective');
const myModule = require('my' + 'module');
const opts = {};


// data will be stored on `result.metadata.requires`
var result = babel.transformFileAsync('/path/to/file', {
plugins:[['detective', opts]]
});

// convenience method to extract metadata
var metadata = detective.metadata(result);

console.log(metadata);
// {
// strings: [
// 'babel-core',
// 'babel-plugin-detective'
// ],
// expressions: [
// {start: 110, end: 125} // loc of 'my' + 'module' expression
// ]
// }
```


## API

### detective.metadata(previousParseResult)

During traversal, the plugin stores each discovered require/import on the Babel metadata object.
It can be extracted manually from `parseResult.metadata.requires`, or you can pass the parse result
to this conveniences method.


## Options


### opts.includeGenerated

Type: `boolean`
Default: `false`

If set to true, it will include `require` calls generated by previous plugins in the
tool chain. This will lead to some duplicate entries if ES2015 import statements are
present in the file. This plugin already scans for ES2015 import statements, so you
only need to use this if there is some other type of generated require statement you
want to know about.

### opts.includeImport

Type: `boolean`
Default: `true`

Include ES2015 imports in the metadata. All ES2015 imports will be of type `string`.

### opts.includeRequire

Type: `boolean`
Default: `true`

Include CommonJS style `require(...)` statements in the metadata. CommonJS require
statements will be pushed on to `metadata.strings` if the argument is a string literal.
For dynamic expressions (`require(foo + bar)`), an object will be pushed on to `metadata.expressions`.
They have `start` and `end` properties that can be used to extract the code directly from the original source.

### opts.word

Type: `string`
Default: `'require'`

The name of the require function. You most likely do not need to change this.

### opts.attachExpressionSource

Type: `boolean`
Default: `false`

Attach the actual expression code to each member of `metadata.expressions`.

```js
expressions: [
{start: 110, end: 125, code: "'my' + 'module'"}
]
```


## License

MIT © [James Talmage](http://github.com/jamestalmage)
11 changes: 11 additions & 0 deletions test/fixtures/fixture.js
@@ -0,0 +1,11 @@
'use strict';

import b from 'b';

require('foo');

require('foo' + 'bar');

__dereq__('baz');

require();
1 change: 1 addition & 0 deletions test/mocha.opts
@@ -0,0 +1 @@
--compilers js:./test/register-babel.js
7 changes: 7 additions & 0 deletions test/register-babel.js
@@ -0,0 +1,7 @@
require('babel-core/register')({
presets: [
'stage-3',
'es2015'
],
only: ['test.js']
});

0 comments on commit d2b166b

Please sign in to comment.