Novice, Practiced, Mastered

    static-analysis

    2.1.1 • Public • Published

    static-analysis

    npm version

    static-analysis Performs Static Analysis On JavaScript Programs To Find Out All Dependencies That Stem From The Given File.

    yarn add static-analysis

    Table Of Contents

    API

    The package is available by importing its default function:

    import staticAnalysis from 'static-analysis'

    The types and externs for Google Closure Compiler via Depack are defined in the _staticAnalysis namespace.

    async staticAnalysis(
      path: string|!Array<string>,
      config: !Config,
    ): !Array<!Detection>

    Detects all dependencies in a file and their dependencies recursively. Returns the array with detections.

    • path* (string | !Array<string>): The path to the file in which to detect dependencies.
    • config* !Config: The configuration options for staticAnalysis.

    It is possible to pass multiple paths or a path to the directory which has index.js or index.jsx files. If the package exports main over module, the hasMain property will be added. This function can be useful to find out all files to pass to the Google Closure Compiler, for example, which is what Depack does to bundle frontend code and compile Node.js packages.

    • The package does not build an AST, it just looks for import and require statements using regular expressions. Therefore, there's also no tree-shaking or complete analysis of the real dependencies.
    • If a source is imported like import fn from '@idio/preact/build/fn, then the analysis will not contain @idio/preact as a node_module dependency with the packageJson, name and version fields, it will only appear as an entry file.

    Config: The configuration options for staticAnalysis.

    Name Type & Description Default
    nodeModules boolean true
    Whether to include packages from node_modules in the output.
    shallow boolean false
    Only report on the entries of node_module dependencies, without analysing their own dependencies.
    soft boolean false
    Do not throw an error when the dependency cannot be found in node_modules.
    mergeSameNodeModules boolean true
    For situation when inner node_modules contain already referenced node_modules, this will ensure that only the top-level ones with the same version are matched. For example, there can be node_modules/a & node_modules/b packages, and the later one can contain node_modules/b/node_modules/a of the same version as a (e.g., if the structure wasn't flattened by something like yarn upgrade). In this case, only the top one is returned.
    fields !Array<string> -
    Any additional fields from package.json files to return.

    For example, for the given file:

    import read from '@wrote/read'
    import { resolve } from 'path'
    import { render } from 'preact'
    import Fixture from '@idio/preact-fixture/src/Test'
     
    const Component = require('./Component');
     
    (async () => {
      const file = await read(resolve('example'))
      render(<Component>
        {file}
        <Fixture />
      </Component>, document.body)
    })()

    Static Analysis can detect matches using the following script:

    /* yarn example/ */
    import staticAnalysis from 'static-analysis'
     
    (async () => {
      const res = await staticAnalysis('example/source.js')
      console.log(res)
    })()
    [ { entry: 'node_modules/@wrote/read/src/index.js',
        packageJson: 'node_modules/@wrote/read/package.json',
        version: '1.0.4',
        name: '@wrote/read',
        from: [ 'example/source.js' ] },
      { internal: 'path', from: [ 'example/source.js' ] },
      { entry: 'node_modules/preact/dist/preact.mjs',
        packageJson: 'node_modules/preact/package.json',
        version: '8.5.2',
        name: 'preact',
        from: [ 'example/source.js' ] },
      { package: '@idio/preact-fixture',
        entry: 'node_modules/@idio/preact-fixture/src/Test.jsx',
        from: [ 'example/source.js' ] },
      { entry: 'example/Component.jsx',
        required: true,
        from: [ 'example/source.js' ] },
      { internal: 'fs',
        from: [ 'node_modules/@wrote/read/src/index.js' ] },
      { entry: 'node_modules/catchment/src/index.js',
        packageJson: 'node_modules/catchment/package.json',
        version: '3.3.0',
        name: 'catchment',
        from: [ 'node_modules/@wrote/read/src/index.js' ] },
      { internal: 'stream',
        from: [ 'node_modules/catchment/src/index.js' ] },
      { entry: 'node_modules/erotic/src/index.js',
        packageJson: 'node_modules/erotic/package.json',
        version: '2.1.1',
        name: 'erotic',
        from: [ 'node_modules/catchment/src/index.js' ] },
      { entry: 'node_modules/@artdeco/clean-stack/src/index.js',
        packageJson: 'node_modules/@artdeco/clean-stack/package.json',
        version: '1.1.1',
        name: '@artdeco/clean-stack',
        from:
         [ 'node_modules/catchment/src/index.js',
           'node_modules/erotic/src/callback.js' ] },
      { package: 'catchment',
        entry: 'node_modules/catchment/src/lib/index.js',
        from: [ 'node_modules/catchment/src/index.js' ] },
      { package: 'erotic',
        entry: 'node_modules/erotic/src/lib.js',
        from:
         [ 'node_modules/erotic/src/index.js',
           'node_modules/erotic/src/callback.js' ] },
      { package: 'erotic',
        entry: 'node_modules/erotic/src/callback.js',
        from: [ 'node_modules/erotic/src/index.js' ] },
      { internal: 'os',
        from: [ 'node_modules/@artdeco/clean-stack/src/index.js' ] } ]

    Detection: The module detection result.

    Name Type Description
    entry string The path to the JavaScript file to be required. If an internal Node.js package is required, it's name is found in the internal field.
    from* !Array<string> The file in which the dependency was found.
    packageJson string The path to the package.json file of the dependency if it's a module.
    name string The name of the package.
    version string The version of the package.
    internal string If it's an internal NodeJS dependency, such as fs or path, contains its name.
    hasMain boolean Whether the entry from the package was specified via the main field and not module field.
    package string If the entry is a library file withing a package, this field contains its name. Same as the name field for the main/module entries.
    required boolean Whether the package was required using the require statement.

    Ignore Node_Modules

    It is possible to ignore node_modules folders. In this case, only dependencies that start with ./ or / will be included in the output.

    import staticAnalysis from 'static-analysis'
     
    (async () => {
      const res = await staticAnalysis('example/source.js', {
        nodeModules: false,
      })
      console.log(res)
    })()
    [ { entry: 'example/Component.jsx',
        required: true,
        from: [ 'example/source.js' ] } ]

    Shallow Node_Modules

    To only report the entry to the dependency from node_modules without analysing its dependency, the shallow options can be set.

    import staticAnalysis from 'static-analysis'
     
    (async () => {
      const res = await staticAnalysis('example/source.js', {
        shallow: true,
      })
      console.log(res)
    })()
    [ { entry: 'node_modules/@wrote/read/src/index.js',
        packageJson: 'node_modules/@wrote/read/package.json',
        version: '1.0.4',
        name: '@wrote/read',
        from: [ 'example/source.js' ] },
      { internal: 'path', from: [ 'example/source.js' ] },
      { entry: 'node_modules/preact/dist/preact.mjs',
        packageJson: 'node_modules/preact/package.json',
        version: '8.5.2',
        name: 'preact',
        from: [ 'example/source.js' ] },
      { package: '@idio/preact-fixture',
        entry: 'node_modules/@idio/preact-fixture/src/Test.jsx',
        from: [ 'example/source.js' ] },
      { entry: 'example/Component.jsx',
        required: true,
        from: [ 'example/source.js' ] } ]

    Soft Mode

    Static Analysis will try to figure out entry points of package dependencies by looking up their package.json in the node_modules folder. If it cannot find this file, an error will be throw. To prevent the error, and exclude the module from appearing the results, the soft mode can be activated.

    With the following file being analysed:

    import missing from 'missing'
    import { render } from 'preact'
     
    render(<div>Hello World</div>)

    The program will throw initially, but will skip the missing dependency in soft mode:

    import staticAnalysis from 'static-analysis'
     
    (async () => {
      try {
        const res = await staticAnalysis('example/missing-dep')
        console.log(res)
      } catch (err) {
        console.log(err)
      }
    })()
     
    ;(async () => {
      const res = await staticAnalysis('example/missing-dep', {
        soft: true,
      })
      console.log('Soft mode on.')
      console.log(res)
    })()
    Error: example/missing-dep.jsx
     [!] Package.json for module missing not found.
        at staticAnalysis (src/index.js:12:13)
        at example/soft.js:5:23
        at Object.<anonymous> (example/soft.js:10:3)
        at Module.p._compile (node_modules/alamode/compile/depack.js:49:18)
        at Object.k.(anonymous function).y._extensions.(anonymous function) [as .js] (node_modules/alamode/compile/depack.js:51:7)
    Soft mode on.
    { entry: 'node_modules/preact/dist/preact.mjs',
        packageJson: 'node_modules/preact/package.json',
        version: '8.5.2',
        name: 'preact',
        from: [ 'example/missing-dep.jsx' ] } ]

    Fields

    To make Static Analysis return any additional fields from package.json files on detected dependencies, they should be specified in the fields config property.

    import staticAnalysis from 'static-analysis'
     
    (async () => {
      const res = await staticAnalysis('example/source', {
        fields: ['license', 'homepage'],
        shallow: true,
      })
      console.log(res)
    })()
    [ { entry: 'node_modules/@wrote/read/src/index.js',
        packageJson: 'node_modules/@wrote/read/package.json',
        version: '1.0.4',
        name: '@wrote/read',
        license: 'MIT',
        homepage: 'https://github.com/wrote/read#readme',
        from: [ 'example/source.js' ] },
      { internal: 'path', from: [ 'example/source.js' ] },
      { entry: 'node_modules/preact/dist/preact.mjs',
        packageJson: 'node_modules/preact/package.json',
        version: '8.5.2',
        name: 'preact',
        license: 'MIT',
        homepage: 'https://github.com/developit/preact',
        from: [ 'example/source.js' ] },
      { package: '@idio/preact-fixture',
        entry: 'node_modules/@idio/preact-fixture/src/Test.jsx',
        from: [ 'example/source.js' ] },
      { entry: 'example/Component.jsx',
        required: true,
        from: [ 'example/source.js' ] } ]

    Multiple Entries

    It's possible to scan multiple files at ones, taking advantage of intermediate caching of results (i.e., after a file has been read ones, it won't be read again, but its from field will contain all files that required it).

    const res = await staticAnalysis([
      'test/fixture/multiple/a.js',
      'test/fixture/multiple/b.js',
    ])
    console.log(res)
    [ { entry: 'test/fixture/multiple/index.js',
        from:
         [ 'test/fixture/multiple/a.js', 'test/fixture/multiple/b.js' ] },
      { entry: 'node_modules/preact/dist/preact.mjs',
        packageJson: 'node_modules/preact/package.json',
        version: '8.5.2',
        name: 'preact',
        from: [ 'test/fixture/multiple/a.js' ] } ]

    sort(
      detected: !Array<!Detection>,
    ): SortReturn

    Sorts the detected dependencies into commonJS modules, packageJsons and internals.

    • detected* !Array<!Detection>: The detected matches.

    SortReturn: The return of the sort function.

    Name Type & Description
    packageJsons* !Array<string>
    commonJsPackageJsons* !Array<string>
    commonJs* !Array<string>
    js* !Array<string>
    internals* !Array<string>
    deps* !Array<string>
    import staticAnalysis, { sort } from 'static-analysis'
     
    (async () => {
      const d = await staticAnalysis('example/source.js')
      const sorted = sort(d)
      console.log(sorted)
    })()
    { commonJsPackageJsons: [],
      packageJsons:
       [ 'node_modules/@wrote/read/package.json',
         'node_modules/preact/package.json',
         'node_modules/catchment/package.json',
         'node_modules/erotic/package.json',
         'node_modules/@artdeco/clean-stack/package.json' ],
      commonJs: [],
      js:
       [ 'node_modules/@wrote/read/src/index.js',
         'node_modules/preact/dist/preact.mjs',
         'node_modules/@idio/preact-fixture/src/Test.jsx',
         'example/Component.jsx',
         'node_modules/catchment/src/index.js',
         'node_modules/erotic/src/index.js',
         'node_modules/@artdeco/clean-stack/src/index.js',
         'node_modules/catchment/src/lib/index.js',
         'node_modules/erotic/src/lib.js',
         'node_modules/erotic/src/callback.js' ],
      internals: [ 'path', 'fs', 'stream', 'os' ],
      deps:
       [ '@wrote/read',
         'preact',
         'catchment',
         'erotic',
         '@artdeco/clean-stack' ] }

    License & Copyright

    Dual licensed under Affero GPL and a commercial license.
    
    - Within the UK: no commercial use is allowed until the
      organisation signs up at
      https://www.technation.sucks/license/.
    - Across the globe: Affero GPL. No companies affiliated
      with Tech Nation in any way (e.g., participation in
      their programs, being part of their network, hiring
      their directors), are allowed to use the software
      unless they sign up.
    
    (c) 2019 Art Deco Code Limited
    
    The COPYING file contains the full text of the public license.
    
    Art Deco © Art Deco for Depack 2019 Tech Nation Visa Tech Nation Visa Sucks

    Install

    npm i static-analysis

    DownloadsWeekly Downloads

    24

    Version

    2.1.1

    License

    SEE LICENSE IN LICENSE

    Unpacked Size

    145 kB

    Total Files

    18

    Last publish

    Collaborators

    • zvr