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

Question: Resolving typescript source files imported from outside specified package

Open harrisonzhu-db opened this issue 1 month ago • 1 comments

Summary

I'm using the dependency-cruiser JS API to recursively construct a list of all source files referenced by an entry point. When this typescript entry point or any of its dependencies imports some module, my IDE is able to jump to the typescript where that is defined, and in essence, I want to do the same thing using dependency-cruiser.

The following code (abstracted)

import { cruise, ICruiseOptions, ICruiseResult } from "dependency-cruiser";
// other imports

async function cruiseDirs() {
  const ARRAY_OF_FILES_AND_DIRS_TO_CRUISE: string[] = [
    getAbsolutePathFromUniverseRelativePath(
      "redash/managed_redash/packages/app/src/open-marketplace/OpenMarketplace.tsx"
    ),
  ];

  try {
    const cruiseOptions: ICruiseOptions = {
      exclude: {
        path: ".*node_modules",
      },
    };
    const cruiseResult = cruise(
      ARRAY_OF_FILES_AND_DIRS_TO_CRUISE,
      cruiseOptions
    );
    console.log(JSON.stringify(cruiseResult.output, null, 2));
  } catch (error) {
    console.error(error);
  }
}
cruiseDirs();

prints out generally what I want. Within redash/managed_redash/packages/app, dependency-cruiser knows how to resolve dependencies to typescript code. In the above example, the OpenMarketplace.tsx file that we start from has these two imports

import { Marketplace } from '@databricks/dbsql/src/app/pages/marketplace/Marketplace';
import { MarketplaceFilterContextProvider } from '@databricks/dbsql/src/app/pages/marketplace/filter/contexts/MarketplaceFilterProvider';

And dependency-cruiser resolves these to ../../../redash/managed_redash/packages/app/src/app/pages/marketplace/filter/contexts/MarketplaceFilterProvider.tsx and ../../../redash/managed_redash/packages/app/src/app/pages/marketplace/Marketplace.tsx

which is what i want!

However, when we import from directories outside of the one specified initially, we run into some issues with resolving imports to their source typescript. Take the following output from dependency-cruiser

  {
    "source": "../../../redash/managed_redash/packages/app/src/app/services/location.ts",
    "dependencies": [
      {
        "module": "@databricks/web-shared/mfe-services",
        "moduleSystem": "es6",
        "dynamic": false,
        "exoticallyRequired": false,
        "resolved": "../../../js/packages/web-shared/mfe-services.mjs",
        "coreModule": false,
        "followable": true,
        "couldNotResolve": false,
        "dependencyTypes": [
          "npm"
        ],
        "matchesDoNotFollow": false,
        "circular": false,
        "valid": true
      },

@databricks/web-shared/mfe-services resolves to some js, which I don’t expect (maybe naively), since the IDE somehow recognizes in import { isRpcSupported } from '@databricks/web-shared/mfe-services'; That isRpcSupported resolves to a specific typescript file.

Further, we also get some unresolved paths:

{
    "source": "@databricks/persona-nav",
    "followable": false,
    "coreModule": false,
    "couldNotResolve": true,
    "matchesDoNotFollow": false,
    "dependencyTypes": [
      "unknown"
    ],
    "dependencies": [],
    "dependents": [
"../../../redash/managed_redash/packages/app/src/app/pages/marketplace/hooks/useMarketplaceTracking.tsx",
      "../../../redash/managed_redash/packages/app/src/app/extensions/edge/components/ApplicationLayout/ApplicationWrapper.tsx",
… CUT FOR BREVITY

These other packages (@databricks/web-shared/…, @databricks/persona-nav) are included in the monorepo root package.json as part of a yarn workspace. Here's the abbreviated structure of our monorepo

universe
├── package.json <- specifies the packages in the yarn workspace
├── redash
│   └── managed_redash
│       ├── packages
│       │   ├── app
│       │   │   └── package.json
├── js
│   ├── packages
│   │   ├── persona-nav
│   │   │   └── package.json
│   │   ├── web-shared
│   │   │   └── package.json

My question: What do I need to add to dependency-cruiser’s options in order to resolve these js files to their typescript source? I tried to require("dependency-cruiser/config-utl/extract-ts-config");, and add redash/managed_redash/packages/app/tsconfig.json to cruise as a parameter, but the output did not change. Here’s the tsconfig of the package that has the entry point that I’m trying to cruise.

{
 "extends": "../../tsconfig.base.json", // <-- this does not include any path aliases
 "compilerOptions": {
   "target": "es2019",
   "lib": ["dom", "dom.iterable", "esnext", "esnext.intl", "es2017.intl", "es2018.intl"],
   "allowJs": true,
   "skipLibCheck": true,
   "strict": true,
   "forceConsistentCasingInFileNames": true,
   "noEmit": true,
   "esModuleInterop": true,
   "module": "esnext",
   "moduleResolution": "node",
   "resolveJsonModule": true,
   "isolatedModules": true,
   "jsx": "preserve",
   "jsxImportSource": "@emotion/react",
   "baseUrl": "./",
   "paths": {
     "@databricks/dbsql/*": ["./*"]
   },
   "types": ["node", "jest", "@testing-library/jest-dom", "ace", "@databricks/config-webpack/env"],
   "incremental": true
 },
 "include": ["next-env.d.ts", "globals.d.ts", "emotion.d.ts", "recoil/testing.d.ts", "**/*.ts", "**/*.tsx"]
}

Context

For more context, I'm building a script that takes some set of typescript entry points and checks if their usages (or any of their dependencies' usages) of a certain library are correct (based on some other validation) with respect to that entry point.

Environment

  • Version used: [email protected]
  • Node version: 20.13.1
  • Operating System and version: Mac OS Sonoma 14.4.1

harrisonzhu-db avatar May 21 '24 08:05 harrisonzhu-db