├── .gitignore
├── .npmignore
├── test
├── fixtures
│ └── module.js
└── index.js
├── LICENSE.md
├── package.json
├── index.js
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 | test
7 | test.js
8 | demo/
9 | .npmignore
10 | LICENSE.md
--------------------------------------------------------------------------------
/test/fixtures/module.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var foo1 = require('object-assign')
3 | var another = require('object-assign').another
4 | import { foo } from './foo'
5 | import { foo as blah } from './blah'
6 | import * as _ from 'lodash'
7 | import defs from 'defaults'
8 | import 'side-effects'
9 | // import 'commented'
10 | /* import { foo } from 'commented2'; */
11 | // require('commented3')
12 | require(__dirname + '/file.js')
13 | require(path.join(__dirname, '/file.js'))
14 |
15 | export default function () {
16 | var b = require('b')
17 | }
18 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2015 Jam3
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
20 | OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "detect-import-require",
3 | "version": "2.0.0",
4 | "description": "list require and import paths from a JavaScript source",
5 | "main": "index.js",
6 | "license": "MIT",
7 | "author": {
8 | "name": "Matt DesLauriers",
9 | "email": "dave.des@gmail.com",
10 | "url": "https://github.com/mattdesl"
11 | },
12 | "standard": {
13 | "ignore": [
14 | "test/fixtures/**/*.js"
15 | ]
16 | },
17 | "dependencies": {
18 | "acorn": "^3.2.0",
19 | "ast-types": "^0.8.16",
20 | "defined": "^1.0.0",
21 | "escodegen": "^1.7.0",
22 | "is-buffer": "^1.1.3"
23 | },
24 | "devDependencies": {
25 | "acorn-jsx": "^3.0.1",
26 | "faucet": "0.0.1",
27 | "standard": "^5.4.1",
28 | "tape": "^4.2.2"
29 | },
30 | "scripts": {
31 | "test": "standard && node test/index.js | faucet"
32 | },
33 | "keywords": [
34 | "import",
35 | "cjs",
36 | "common",
37 | "js",
38 | "commonjs",
39 | "imports",
40 | "require",
41 | "requires",
42 | "detective",
43 | "node",
44 | "ast",
45 | "walk",
46 | "find",
47 | "module",
48 | "modules"
49 | ],
50 | "repository": {
51 | "type": "git",
52 | "url": "git://github.com/Jam3/detect-import-require.git"
53 | },
54 | "homepage": "https://github.com/Jam3/detect-import-require",
55 | "bugs": {
56 | "url": "https://github.com/Jam3/detect-import-require/issues"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var detect = require('../')
2 | var test = require('tape')
3 | var fs = require('fs')
4 | var path = require('path')
5 |
6 | var filename = path.resolve(__dirname, 'fixtures', 'module.js')
7 | var src = fs.readFileSync(filename, 'utf8')
8 |
9 | test('like the detective module, but for CommonJS + imports', function (t) {
10 | t.deepEqual(detect(src), [
11 | 'path', 'object-assign', 'object-assign',
12 | './foo', './blah', 'lodash', 'defaults',
13 | 'side-effects', 'b'
14 | ])
15 |
16 | t.deepEqual(detect(src, { imports: false }), [
17 | 'path', 'object-assign', 'object-assign', 'b'
18 | ])
19 |
20 | t.deepEqual(detect(src, { imports: false, requires: false }), [])
21 |
22 | t.deepEqual(detect(src, { imports: true, requires: false }), [
23 | './foo', './blah', 'lodash', 'defaults', 'side-effects'
24 | ])
25 | t.end()
26 | })
27 |
28 | test('advanced mode', function (t) {
29 | t.deepEqual(detect.find(src).expressions, [
30 | "__dirname + '/file.js'",
31 | "path.join(__dirname, '/file.js')"
32 | ])
33 |
34 | t.deepEqual(detect.find(src).strings, [
35 | 'path', 'object-assign', 'object-assign',
36 | './foo', './blah', 'lodash', 'defaults',
37 | 'side-effects', 'b'
38 | ])
39 |
40 | t.deepEqual(detect.find(src, { requires: false }).expressions, [])
41 | t.end()
42 | })
43 |
44 | test('empty file', function (t) {
45 | t.deepEqual(detect(''), [])
46 | t.end()
47 | })
48 |
49 | test('supports Buffer type', function (t) {
50 | var buf = fs.readFileSync(filename)
51 | t.deepEqual(detect(buf), [
52 | 'path', 'object-assign', 'object-assign',
53 | './foo', './blah', 'lodash', 'defaults',
54 | 'side-effects', 'b'
55 | ])
56 | t.end()
57 | })
58 |
59 | test('supports custom AST input', function (t) {
60 | var jsx = "import 'foo'; ReactDOM.render(
Hello World
, document.getElementById('root'));"
61 | var acorn = require('acorn-jsx/inject')(require('acorn'))
62 | var ast = acorn.parse(jsx, {
63 | ecmaVersion: 6,
64 | sourceType: 'module',
65 | allowReserved: true,
66 | allowReturnOutsideFunction: true,
67 | allowHashBang: true,
68 | plugins: {
69 | jsx: true
70 | }
71 | })
72 | t.deepEqual(detect(ast), [
73 | 'foo'
74 | ])
75 | t.end()
76 | })
77 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var acorn = require('acorn')
2 | var escodegen = require('escodegen')
3 | var defined = require('defined')
4 | var isBuffer = require('is-buffer')
5 | var types = require('ast-types')
6 |
7 | var regexRequire = /\brequire\b/
8 | var regexImport = /\bimport\b/
9 | var regexBoth = /\b(import|require)\b/
10 |
11 | module.exports = detectImportRequire
12 | function detectImportRequire (src, opts) {
13 | return findImportRequire(src, opts).strings
14 | }
15 |
16 | module.exports.find = findImportRequire
17 | function findImportRequire (src, opts) {
18 | opts = opts || {}
19 |
20 | // allow Node Buffer
21 | if (isBuffer(src)) {
22 | src = src.toString()
23 | }
24 |
25 | if (typeof src !== 'string' && !src) {
26 | throw new Error('src option must be a string, Buffer or AST')
27 | }
28 |
29 | var imports = defined(opts.imports, true)
30 | var requires = defined(opts.requires, true)
31 |
32 | var results = {
33 | strings: [],
34 | expressions: [],
35 | nodes: []
36 | }
37 |
38 | var ast
39 | if (typeof src === 'string') {
40 | // quick regex test before we parse entire AST
41 | src = (src || '')
42 | var regex = regexBoth
43 | if (imports && !requires) regex = regexImport
44 | else if (requires && !imports) regex = regexRequire
45 | if (!regex.test(src)) {
46 | return results
47 | }
48 |
49 | // now parse
50 | ast = acorn.parse(src, {
51 | ecmaVersion: 6,
52 | sourceType: 'module',
53 | allowReserved: true,
54 | allowReturnOutsideFunction: true,
55 | allowHashBang: true
56 | })
57 | } else {
58 | // assume ast is given
59 | ast = src
60 | }
61 |
62 | var importDeclaration, callExpression
63 | if (imports) {
64 | importDeclaration = function (path) {
65 | var node = path.node
66 | if (node.source.type === 'Literal') {
67 | results.strings.push(node.source.value)
68 | }
69 | results.nodes.push(node)
70 | this.traverse(path)
71 | }
72 | }
73 |
74 | if (requires) {
75 | callExpression = function (path) {
76 | var node = path.node
77 | if (!isRequire(node)) return false
78 | if (node.arguments.length) {
79 | if (node.arguments[0].type === 'Literal') {
80 | results.strings.push(node.arguments[0].value)
81 | } else {
82 | results.expressions.push(escodegen.generate(node.arguments[0]))
83 | }
84 | }
85 | results.nodes.push(node)
86 | this.traverse(path)
87 | }
88 | }
89 |
90 | types.visit(ast, {
91 | visitImportDeclaration: importDeclaration,
92 | visitCallExpression: callExpression
93 | })
94 |
95 | return results
96 | }
97 |
98 | function isRequire (node) {
99 | return node.callee.type === 'Identifier' &&
100 | node.callee.name === 'require'
101 | }
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # detect-import-require
2 |
3 | [](http://github.com/badges/stability-badges)
4 |
5 | This is like [detective](https://www.npmjs.com/package/detective), but with a narrow focus and thin API, specifically aimed at supporting either `import` and/or `require` statements, and not much more.
6 |
7 | ## Install
8 |
9 | ```sh
10 | npm install detect-import-require --save
11 | ```
12 |
13 | ## Example
14 |
15 | Given the following file:
16 |
17 | `source.js`
18 | ```js
19 | var foo = require('a').foo
20 | var bar = require('./blah.js')
21 | import { uniq } from 'lodash'
22 | import { resolve } from 'path'
23 | ```
24 |
25 | ```js
26 | var fs = require('fs')
27 | var detect = require('detect-import-require')
28 |
29 | var src = fs.readFileSync('source.js', 'utf8')
30 | console.log(detect(src))
31 | //=> [ 'a', './blah.js', 'lodash', 'path' ]
32 | ```
33 |
34 | See [Custom AST](#custom-ast) for details on parsing additional language syntax, such as JSX or async/await.
35 |
36 | ## Usage
37 |
38 | [](https://www.npmjs.com/package/detect-import-require)
39 |
40 | #### `modules = detect(src, [opt])`
41 |
42 | Returns an array of module names (require paths) from the given `src` String, Buffer or AST. By default, looks for `import` and `require` statements. Results are not de-duplicated, and are in the order they are found.
43 |
44 | Options:
45 |
46 | - `imports` (Boolean) - whether to look for `import` statements, default true
47 | - `requires` (Boolean) - whether to look for `require` statements, default true
48 |
49 | #### `modules = detect.find(src, [opt])`
50 |
51 | Takes the same options as above, but returns an object with the following additional data:
52 |
53 | ```js
54 | {
55 | strings: [],
56 | expressions: [],
57 | nodes: []
58 | }
59 | ```
60 |
61 | Where `strings` is the array of module names, `expressions` is an array of expressions from dynamic `require()` statements, and `nodes` is an array of AST nodes for each found require/import statement.
62 |
63 | Expressions do not appear in imports, and look like this:
64 |
65 | ```js
66 | [
67 | "path.join(__dirname, '/foo.js')",
68 | "__dirname + '/file.js'"
69 | ]
70 | ```
71 |
72 | ## Custom AST
73 |
74 | You can also pass a parsed AST, e.g. if you have a special build of acorn or want full control over parsing options. Here is an example with JSX:
75 |
76 | ```js
77 | var detect = require('detect-import-require')
78 | var acorn = require('acorn-jsx');
79 | var jsx = [
80 | "import 'foo';",
81 | "ReactDOM.render(",
82 | "Hello World
,",
83 | "document.getElementById('root')",
84 | ");"
85 | ].join('\n');
86 |
87 | var ast = acorn.parse(jsx, {
88 | ecmaVersion: 6,
89 | sourceType: 'module',
90 | allowReserved: true,
91 | allowReturnOutsideFunction: true,
92 | allowHashBang: true,
93 | plugins: {
94 | jsx: true
95 | }
96 | })
97 |
98 | detect(ast)
99 | // => [ 'foo' ]
100 | ```
101 |
102 | ## License
103 |
104 | MIT, see [LICENSE.md](http://github.com/Jam3/detect-import-require/blob/master/LICENSE.md) for details.
105 |
--------------------------------------------------------------------------------