<commit_before>import * as fs from 'fs';
import * as path from 'path';
import { Config, FileToData, FileToDependency } from './../types';
import traverse from '@babel/traverse';

export default (filesData: FileToData, config: Config): FileToDependency => {
    const root = config.root;
    const result = Object.entries(filesData).reduce(
        (acc, [filePath, data]) => {
            if (!data.ast) {
                return acc;
            }

            const imports = getImports(data.ast());
            const dependencies = imports
                .map(i => extractPathFromImportString(i, filePath, [root]))
                .filter(i => i) as string[];

            return {
                ...acc,
                [filePath]: dependencies,
            };
        },
        {} as FileToDependency,
    );

    return result;
};

const getImports = (ast: any) => {
    const staticImports: string[] = [];
    const dynamicImports: string[] = [];

    traverse(ast, {
        enter(path: any) {
            if (path.node.type === 'ImportDeclaration') {
                staticImports.push(path.node.source.value);
            } else if (
                path.node.type === 'CallExpression' &&
                path.node.callee.type === 'Import' &&
                path.node.arguments &&
                path.node.arguments.length > 0
            ) {
                dynamicImports.push(path.node.arguments[0].value);
            }
        },
    });

    return [...staticImports, ...dynamicImports];
};

const resolveImport = (potentialImportPaths: string[]): string | undefined => {
    const result = potentialImportPaths
        .reduce(
            (acc, importPath) => [
                ...acc,
                path.join(importPath, 'index.js'),
                importPath + '.js',
                importPath,
            ],
            [] as string[],
        )
        .find(i => fs.existsSync(i));

    return result;
};

const extractPathFromImportString = (
    importString: string,
    filePath: string,<commit_msg>Add support for require and reexport when calculating imports<commit_after>import * as fs from 'fs';
import * as path from 'path';
import { Config, FileToData, FileToDependency } from './../types';
import traverse from '@babel/traverse';

export default (filesData: FileToData, config: Config): FileToDependency => {
    const root = config.root;
    const result = Object.entries(filesData).reduce(
        (acc, [filePath, data]) => {
            if (!data.ast) {
                return acc;
            }

            const imports = getImports(data.ast());
            const dependencies = imports
                .map(i => extractPathFromImportString(i, filePath, [root]))
                .filter(i => i) as string[];

            return {
                ...acc,
                [filePath]: dependencies,
            };
        },
        {} as FileToDependency,
    );

    return result;
};

const getImports = (ast: any) => {
    const staticImports: string[] = [];
    const dynamicImports: string[] = [];

    traverse(ast, {
        enter(path: any) {
            const isStaticImport =
                path.node.type === 'ImportDeclaration' ||
                ((path.node.type === 'ExportNamedDeclaration' ||
                    path.node.type === 'ExportAllDeclaration') &&
                    path.node.source);
            const isDynamicImport =
                path.node.type === 'CallExpression' &&
                (path.node.callee.type === 'Import' ||
                    (path.node.callee.type === 'Identifier' &&
                        path.node.callee.name === 'require')) &&
                path.node.arguments &&
                path.node.arguments.length > 0;

            if (isStaticImport) {
                staticImports.push(path.node.source.value);
            } else if (isDynamicImport) {
                dynamicImports.push(path.node.arguments[0].value);
            }
        },
    });

    return [...staticImports, ...dynamicImports];
};

const resolveImport = (potentialImportPaths: string[]): string | undefined => {
    const result = potentialImportPaths
        .reduce(
            (acc, importPath) => [
                ...acc,
                path.join(importPath, 'index.js'),
                importPath + '.js',
                importPath,
            ],
            [] as string[],
        )
        .find(i => fs.existsSync(i));

    return result;
};

const extractPathFromImportString = (
    importString: string,
    filePath: string,
{'fraction_non_alphanumeric': 0.13433495360141406, 'fraction_numerical': 0.0008837825894829872, 'mean_word_length': 1.6850533807829182, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3379402', 'n_tokens_mistral': 1228, 'n_tokens_neox': 1175, 'n_words': 266}