dependency-cruiser icon indicating copy to clipboard operation
dependency-cruiser copied to clipboard

Question: Ignore/Skip Re-Exports?

Open belyanskii opened this issue 1 year ago • 3 comments

Summary

Is there any way to ignore or skip re-exports?

Context

I have some kind of mono repository, based on pnpm workspaces, the hierarchy looks like this

monorepo/
    packages/
        ui-controls/
            src/index.ts
        core-modules/
            src/index.ts
    projects/
        website/
        admin-panel/
        mobile-app/

I try to cruise file from one of my projects, like header.tsx

import { UserInfo, Button } from '@monorepo/ui-controls';
import { login } from '@monorepo/core-modules';

export const Header = funcrion Header(props) {
    return (
        <div class='header'>
            {
                props.username
                    ? (<UserInfo username={props.username} />)
                    : (<Button onClick={login} /> )
            }
        </div>
    );
};
$ /monorepo/projects/website/: depcruise "./src/components/header.tsx" -T json -f depcru.json --config .dependency-cruiser.js

And because I use index.ts in packages for re-export, i see some kind of this in "dependencies" section:

{
    "dynamic": false,
    "module": "@monorepo/ui-controls",
    "moduleSystem": "es6",
    "exoticallyRequired": false,
    "resolved": "packages/ui-controls/src/index.ts",
    "coreModule": false,
    "followable": true,
    "couldNotResolve": false,
    "dependencyTypes": [
        "npm"
    ],
    "matchesDoNotFollow": false,
    "circular": false,
    "valid": true
},

And below of course I can already see the dependencies of index.ts, but what I really need is to know that my header depends on the UserInfo, Button and login, and not from the whole package

Environment

  • Version used: 11.11.0
  • Node version: v16.13.2
  • Operating System and version: macOS Monterey 12.4

belyanskii avatar Jul 19 '22 23:07 belyanskii

@belyanskii do I understand your question correctly you want this situation: ist

... (where the index.ts's are 'barrel' files with no functionality, re-exporting everything they import) to be represented like this?:

soll

Technically this is not impossible, but header.tsx does rely on the index.ts's and not on the modules it shields as an interface.

What is the reason the code in your example doesn't directly import UserInfo, Button, login and relies on an intermediate index.ts instead?

sverweij avatar Jul 23 '22 07:07 sverweij

@sverweij Yes, you understood me correctly! index.ts we use because it's just more convenient :( U don't need to set whole path to component/module/helper, just use re-export and all the imports in the project become the same. The team developing the package gives the API, and where the files are located inside is not so important

Why do I need this functionality at all?

When i edit file, like button.ts in my example, our Ci-machinery run builds and tests of whole code of all packages and projects, and this is a little too much )

My task is to build a graph to understand exactly which files depend on the button.ts and decide which tests and builds to run.

If dependency-cruiser could ignore re-exports, it would be pretty easy, just cruise whole project and take all sources with buttin.ts in deps.

What other option do I see?

When dependency-cruiser read imports, they can make verbose variant of result and show AST parsed imports, like this


// take some .ts file and get AST
const node = ts.createSourceFile(
    'x.ts',
    fs.readFileSync('button.ts', 'utf8'),
    ts.ScriptTarget.Latest
);

const importDecl = {};

node.forEachChild(child => {
    if (ts.SyntaxKind[child.kind] === 'ImportDeclaration') {
        const clause = [];

        if (child.importClause.namedBindings) {
            child.importClause.namedBindings.elements.map(
                el => clause.push(el.name.escapedText)
            );
        } else {
            clause.push(child.importClause.name.escapedText);
        }

        importDecl[child.moduleSpecifier.text] = clause;
    }
});

It's old example, but idea is to get:

{
   '@monorepo/ui-controls': ['Button', 'UserInfo'],
   '@monorepo/core-modules': ['login']
}

Here we do not ignore re-exports and do not go deeper, but simply supplement the knowledge that is imported from the file, and if it were possible, then we would get all the same, but with additional information

{
    "dynamic": false,
    "module": "@monorepo/ui-controls",
    "moduleSystem": "es6",
    "resolvedImports": ["Button", "UserInfo"], // like this o_O
    "exoticallyRequired": false,
    "resolved": "packages/ui-controls/src/index.ts",
    "coreModule": false,
    "followable": true,
    "couldNotResolve": false,
    "dependencyTypes": [
        "npm"
    ],
    "matchesDoNotFollow": false,
    "circular": false,
    "valid": true
},

belyanskii avatar Jul 23 '22 14:07 belyanskii

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

github-actions[bot] avatar Jul 31 '22 03:07 github-actions[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

github-actions[bot] avatar Aug 08 '22 03:08 github-actions[bot]

whoops - I've missed a few stale notifications - re-open please 😬

sverweij avatar Aug 14 '22 17:08 sverweij

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

github-actions[bot] avatar Aug 22 '22 04:08 github-actions[bot]

I stumbled upon this package this week, and this is the main blocker for me using it effectively. I am not familiar with the codebase, but I am willing to help contribute for this functionality.

william-will-angi avatar Dec 05 '23 16:12 william-will-angi

@belyanskii do I understand your question correctly you want this situation:我是否正确理解你的问题你想要这种情况: ist

... (where the index.ts's are 'barrel' files with no functionality, re-exporting everything they import) to be represented like this?:...(其中 index.ts 是没有功能的“桶”文件,重新导出它们导入的所有内容)像这样表示?:

soll

Technically this is not impossible, but header.tsx does rely on the index.ts's and not on the modules it shields as an interface.从技术上讲,这并非不可能,但 header.tsx 确实依赖于 index.ts ,而不是它作为接口屏蔽的模块。

What is the reason the code in your example doesn't directly import UserInfo, Button, login and relies on an intermediate index.ts instead?您的示例中的代码不直接导入 UserInfo、Button、login 而是依赖中间的 index.ts 的原因是什么?

Is there any update on this issue? I'm experiencing a similar need and would greatly appreciate any progress made.

El-Chiang avatar Feb 22 '24 10:02 El-Chiang