Dependency-cruiser: Typescript Union Types : Cannot read property 'kind' of undefined

Created on 12 Jul 2019  路  10Comments  路  Source: sverweij/dependency-cruiser

Analyze failed when ts file have union types.

Current Behavior

Analyze stop without report on this error :

ERROR: Extracting dependencies ran afoul of...

Cannot read property 'kind' of undefined
... in src/...

Steps to Reproduce (for bugs)

export interface request {
method?: "get" | "post" | "patch" | "put" | "delete" | "head" | "options";
}

or :

test(sort: "none" | "ascending" | "descending" )

Your Environment

  • Version used: 4.27.1
  • Node version: 8.9.4
  • Operating System and version: Debian 9
  • typecript: 3.4.5
bug

All 10 comments

hi @heurtemattes - thanks for raising this! I'll dig into it over the weekend.

Could you provide the command line invocation you used and your dependency-cruiser configuration? It'll help narrowing down the root cause.

? What format do you want your config file to be in? JSON
? Do you want to use a preset or a self-contained configuration? self-contained
? Looks like you're using TypeScript. Use a 'tsconfig.json'? Yes
? Full path to 'tsconfig.json': ./tsconfig.json
? Also regard TypeScript dependencies that exist only before compilation? Yes

.dependency-cruiser.json

{
"forbidden": [
/* rules from the 'recommended' preset: */
{
"name": "no-circular",
"severity": "warn",
"comment": "This dependency is part of a circular relationship. You might want to revise your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ",
"from": {},
"to": {
"circular": true
}
},
{
"name": "no-orphans",
"severity": "info",
"comment": "This is an orphan module - it's likely not used (anymore?). Either use it or remove it. If it's logical this module is an orphan (i.e. it's a config file), add an exception for it in your dependency-cruiser configuration.",
"from": {
"orphan": true,
"pathNot": "\.d\.ts$"
},
"to": {}
},
{
"name": "no-deprecated-core",
"comment": "A module depends on a node core module that has been deprecated. Find an alternative - these are bound to exist - node doesn't deprecate lightly.",
"severity": "warn",
"from": {},
"to": {
"dependencyTypes": [
"core"
],
"path": "^(punycode|domain|constants|sys|_linklist|_stream_wrap)$"
}
},
{
"name": "no-deprecated-npm",
"comment": "This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later version of that module, or find an alternative. Deprecated modules are a security risk.",
"severity": "warn",
"from": {},
"to": {
"dependencyTypes": [
"deprecated"
]
}
},
{
"name": "no-non-package-json",
"severity": "error",
"comment": "This module depends on an npm package that isn't in the 'dependencies' section of your package.json. That's problematic as the package either (1) won't be available on live (2 - worse) will be available on live with an non-guaranteed version. Fix it by adding the package to the dependencies in your package.json.",
"from": {},
"to": {
"dependencyTypes": [
"npm-no-pkg",
"npm-unknown"
]
}
},
{
"name": "not-to-unresolvable",
"comment": "This module depends on a module that cannot be found ('resolved to disk'). If it's an npm module: add it to your package.json. In all other cases you likely already know what to do.",
"severity": "error",
"from": {},
"to": {
"couldNotResolve": true
}
},
{
"name": "no-duplicate-dep-types",
"comment": "Likley this module depends on an external ('npm') package that occurs more than once in your package.json i.e. bot as a devDependencies and in dependencies. This will cause maintenance problems later on.",
"severity": "warn",
"from": {},
"to": {
"moreThanOneDependencyType": true
}
},

    /* rules you might want to tweak for your specific situation: */
    {
        "name": "not-to-test",
        "comment": "This module depends on code within a folder that should only contain tests. As tests don't implement functionality this is odd. Either you're writing a test outside the test folder or there's something in the test folder that isn't a test.",
        "severity": "error",
        "from": {
            "pathNot": "^(test|spec)"
        },
        "to": {
            "path": "^(test|spec)"
        }
    },
    {
        "name": "not-to-spec",
        "comment": "This module depends on a spec (test) file. The sole responsibility of a spec file is to test code. If there's something in a spec that's of use to other modules, it doesn't have that single responsibility anymore. Factor it out into (e.g.) a separate utility/ helper or a mock.",
        "severity": "error",
        "from": {},
        "to": {
            "path": "\\.spec\\.(js|ts|ls|coffee|litcoffee|coffee\\.md)$"
        }
    },
    {
        "name": "not-to-dev-dep",
        "severity": "error",
        "comment": "This module depends on an npm package from the 'devDependencies' section of your package.json. It looks like something that ships to production, though. To prevent problems with npm packages that aren't there on production declare it (only!) in the 'dependencies'section of your package.json. If this module is development only - add it to the from.pathNot re of the not-to-dev-dep rule in the dependency-cruiser configuration",
        "from": {
            "path": "^(src|app|lib)",
            "pathNot": "\\.spec\\.(js|ts|ls|coffee|litcoffee|coffee\\.md)$"
        },
        "to": {
            "dependencyTypes": [
                "npm-dev"
            ]
        }
    },
    {
        "name": "optional-deps-used",
        "severity": "info",
        "comment": "This module depends on an npm package that is declared as an optional dependency in your package.json. As this makes sense in limited situations only, it's flagged here. If you're using an optional dependency here by design - add an exception to yourdepdency-cruiser configuration.",
        "from": {},
        "to": {
            "dependencyTypes": [
                "npm-optional"
            ]
        }
    },
    {
        "name": "peer-deps-used",
        "comment": "This module depends on an npm package that is declared as a peer dependency in your package.json. This makes sense if your package is e.g. a plugin, but in other cases - maybe not so much. If the use of a peer dependency is intentional add an exception to your dependency-cruiser configuration.",
        "severity": "warn",
        "from": {},
        "to": {
            "dependencyTypes": [
                "npm-peer"
            ]
        }
    }
],
"options": {
    /* conditions specifying which files not to follow further when encountered:
       - path: a regular expression to match
       - dependencyTypes: see https://github.com/sverweij/dependency-cruiser/blob/develop/doc/rules-reference.md#dependencytypes
         for a complete list
    */
    "doNotFollow": {
        // "path": "node_modules",
        "dependencyTypes": [
            "npm",
            "npm-dev",
            "npm-optional",
            "npm-peer",
            "npm-bundled",
            "npm-no-pkg"
        ]
    }

    /* conditions specifying which dependencies to exclude 
       - path: a regular expression to match
       - dynamic: a boolean indicating whether to ignore dynamic (true) or static (false) dependencies.
                leave out if you want to exclude neither (recommended!)
    */
    // , "exclude" : {
    //   "path": ""
    //   , "dynamic": true
    // }

    /* pattern specifying which files to include (regular expression) 
       dependency-cruiser will skip everything not matching this pattern
    */
    // , "includeOnly" : ""

    /* list of module systems to cruise */
    // , "moduleSystems": ["amd", "cjs", "es6", "tsd"]

    /* prefix for links in html and svg output (e.g. https://github.com/you/yourrepo/blob/develop/) */
    // , "prefix": ""

    /* if true detect dependencies that only exist before typescript-to-javascript compilation */
    , "tsPreCompilationDeps": true

    /* if true combines the package.jsons found from the module up to the base
       folder the cruise is initiated from. Useful for how (some) mono-repos
       manage dependencies & dependency definitions.
     */
    // , "combinedDependencies": false

    /* if true leave symlinks untouched, otherwise use the realpath */
    // , "preserveSymlinks": false

    /* Typescript project file ('tsconfig.json') to use for
       (1) compilation and
       (2) resolution (e.g. with the paths property)

       The (optional) fileName attribute specifies which file to take (relative to dependency-cruiser's
       current working directory. When not provided defaults to './tsconfig.json'.
     */
    , "tsConfig": {
        "fileName": "./tsconfig.json"
    }

    /* Webpack configuration to use to get resolve options from.

      The (optional) fileName attribute specifies which file to take (relative to dependency-cruiser's
      current working directory. When not provided defaults to './webpack.conf.js'.

      The (optional) `env` and `args` attributes contain the parameters to be passed if
      your webpack config is a function and takes them (see webpack documentation
      for details)
     */
    // , "webpackConfig": {
    //    "fileName": "./webpack.conf.js"
    //    , "env": {}
    //    , "args": {}
    // }

    /* How to resolve external modules - use "yarn-pnp" if you're using yarn's Plug'n'Play.
       otherwise leave it out (or set to the default, which is 'node_modules')
    */
    // , "externalModuleResolutionStrategy": "node_modules"
}

}
// generated: [email protected] on 2019-07-12T09:32:40.054Z

depcruise --validate .dependency-cruiser.json src

hi @heurtemattes I wasn't able to reproduce the problem with the input you provided (the two samples that use union types, with several versions of the typescript compiler), so I suspect dependency-cruiser tripped over something else in that source file.

Could you share the complete source file (anonymised if necessary) dependency-cruiser tripped over?

There is a spot in the code that didn't check for existence before retrieving its kind property. It's in a piece that detects type imports (e.g. const method: import('./http-things').request;) , though. I put some checks around it (PR + beta release coming up), but I'm not sure it'd fix the issue you have.

You can check if the extra checks solve the issue by using [email protected] [email protected], which was just published to npmjs.

(Even if it fixes the issue, I'd still need a sample that reproduces the issue to put into a unit test to prevent future regression).

Hi,

It seems, I have some regression on other stuff : Import unsed, ...

log :
ERROR: Extracting dependencies ran afoul of...

Cannot read property 'some' of undefined
... in

You can test on this code source : https://github.com/diplomatiegouvfr/hornet-js

@heurtemattes thanks - I'll be checking it out. hornet-js seems like a pretty big monorepo - is there one specific part/ subfolder this occurs on or is it all over the place?

Subfolder : hornet-js-core
I use this one for my tests

  1. I've found (and fixed) the regression - in the node version you're using (8.9.4) the core module module doesn't have the property builtInModules which later versions of node 8 (i.e. current latest: 8.16.0) and even 6 do - I'll revert back to using an external module for it.
  2. I haven't been able to reproduce the original issue with the versions you supplied above (node 8.9.4, typescript 3.4.5). So I've tried some other combinations - and with typescript versions between 2.7.2 and 2.8.4 the problem occurs (>2.9 it works ok, <2.7 trips over features in hornet's tsconfig) - so my guess is the typescript version that's installed in the same spot as dependency-cruiser on your machine is somewhere within that range.

The good news is that with the fix in #168 (and after reverting #170 ) I can't reproduce the problem on hornet-js-core anymore => you can try with [email protected] I'll publish later today.

(Out of curiosity: What's the reason to use older versions of node 8 and typescript?)

Work fine for me.

Great investigative work ;-D

I didn't pay attention to my typescript version in global because we use a build tool with typescript inside.

We use node8 actually for our legacy, but for sure we're migrating.

the regular release [email protected] (released yesterday) now contains the fix for this issue as well.

Was this page helpful?
0 / 5 - 0 ratings