diff --git a/README.md b/README.md index 7dbaf8c..449fbdc 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ const dependencies = detective(mySourceCode); - `mixedImports`: (default: `false`) Include CJS imports in dependency list - `skipAsyncImports`: (default: `false`) Whether or not to omit async imports (import('foo')) - `jsx`: (default: `false`) Enable parsing of JSX +- `onFile`: A callback that will be called before the file is processed. Intended for use with [`dependency-tree`](https://github.com/dependents/node-dependency-tree). Passed an object argument with properties `options` (echoing any options passed in, e.g., by [`precinct`](https://github.com/dependents/node-precinct)), `src` (source code for file as string), `ast` (parsed AST object for the file source), and `walker` (a `Walker` instance from [`source-walk`](https://github.com/dependents/node-source-walk) configured for TypeScript to which you can pass the `ast` or `src`). +- `onAfterFile`: Similar to `onFile`, but the callback is also passed an object property `dependencies`, a string array with the extracted dependencies. ## License diff --git a/index.js b/index.js index e6600cc..a1f99d4 100644 --- a/index.js +++ b/index.js @@ -29,6 +29,14 @@ module.exports = (src, options = {}) => { const walker = new Walker(walkerOptions); const dependencies = []; + // Pre-parse the source to get the AST to pass to `onFile`, + // then reuse that AST below in our walker walk. + const ast = typeof src === 'string' ? walker.parse(src) : src; + + if (options.onFile) { + options.onFile({ options, src, ast, walker }); + } + walker.walk(src, node => { switch (node.type) { case 'ImportExpression': { @@ -100,6 +108,10 @@ module.exports = (src, options = {}) => { } }); + if (options.onAfterFile) { + options.onAfterFile({ options, src, ast, walker, dependencies }); + } + return dependencies; }; diff --git a/test/test.js b/test/test.js index d22f8f2..501648e 100644 --- a/test/test.js +++ b/test/test.js @@ -37,6 +37,47 @@ describe('detective-typescript', () => { assert.equal(deps[0], 'mylib'); }); + it('calls onFile callback', () => { + let onFileCalledArgs; + const onFile = (...args) => { + onFileCalledArgs = args; + }; + + const src = 'import {foo, bar} from "mylib";'; + + detective(src, { onFile }); + + assert.ok(onFileCalledArgs); + assert.ok(onFileCalledArgs[0]); + assert.equal(onFileCalledArgs[0].src, src); + assert.ok(typeof onFileCalledArgs[0].ast === 'object'); + assert.ok(typeof onFileCalledArgs[0].walker === 'object'); + + assert.ok(typeof onFileCalledArgs[0].options === 'object'); + assert.equal(onFileCalledArgs[0].options.onFile, onFile); + }); + + it('calls onAfterFile callback', () => { + let onAfterFileCalledArgs; + const onAfterFile = (...args) => { + onAfterFileCalledArgs = args; + }; + + const src = 'import {foo, bar} from "mylib";'; + + detective(src, { onAfterFile }); + + assert.ok(onAfterFileCalledArgs); + assert.ok(onAfterFileCalledArgs[0]); + assert.equal(onAfterFileCalledArgs[0].src, src); + assert.ok(typeof onAfterFileCalledArgs[0].ast === 'object'); + assert.ok(typeof onAfterFileCalledArgs[0].walker === 'object'); + assert.ok(Array.isArray(onAfterFileCalledArgs[0].dependencies)); + + assert.ok(typeof onAfterFileCalledArgs[0].options === 'object'); + assert.equal(onAfterFileCalledArgs[0].options.onAfterFile, onAfterFile); + }); + it('retrieves the re-export dependencies of modules', () => { const deps = detective('export {foo, bar} from "mylib";'); assert.equal(deps.length, 1);