npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dschnare/anna

v3.0.0

Published

Anna is a file type agnostic static analyzer

Downloads

8

Readme

Anna

Anna is a file type agnostic static analyzer.

Installation

npm install @dschnare/anna --save-dev

Quick Start

Asset Analysis

Enumerate all assets referenced in a JavaScript source file. Any string literal of the form ('|")path/to/file.ext('|") will be interpreted as an asset.

const Anna = require('@dschnare/anna')

Anna
  // Create an instance of Anna
  .create()
  // Install the provided jsAssets plugin that will look for assets in
  // string literals. We tell Anna to save the result to the 'assets'
  // property of the result object and only analyze files with an '.js'
  // extension.
  .use('assets', /\.js$/, Anna.jsAssets())
  .analyze('src/compoents/Badge/index.js')
  .then(result => {
    console.log('Analysis done!')
    // Log the asset objects, where each asset object has the following
    // shape: { assetUrl, assetFile }
    // NOTE: assetFile can be null if a file was not found.
    console.log('assets:', result.assets)
  })
  .catch(error => console.error(error))

One of Anna's main goals was to make asset colocation easy. We can quite easily modify the example above so that Anna will copy our assets to a directory for us. In this example all assets will be copied to dist/${assetUrl}.

Anna
  .create()
  .use('assets', /\.js$/, Anna.jsAssets())
  .analyze('src/compoents/Badge/index.js')
  .then(result => {
    return Anna.copyAssets(result.assets, 'dist')
      // Pass the result object on so that other things can be done with it
      // further down the Promise chain.
      .then(() => result)
  })
  .catch(error => console.error(error))

Dependency Analysis

What about dependencies that are imported or required? Anna can handle that out of the box too. Out of the box Anna has analyzers that return arrays of absolute file paths to the dependent files for common dependency import patterns.

Anna
  .create()
  // Match ES2015 import statements and CommonJS require statements.
  .use('deps.js', /\.(js|ts|coffee)$/, Anna.jsDependencies())
  // Match @import, less @import statements, stylus @require statements and
  // index styles.
  .use('deps.css', /\.(css|less|sass|scss|styl)/, Anna.cssDependencies())
  .analyze([
    'src/components/Badge/index.js',
    'src/components/Badge/style.css'
  ])
  .then(result => {
    // logs: { js: [...], css: [...] }
    console.log(result.deps)
  })
  // If a dependency cannot be resolved then an error is thrown.
  .catch(error => console.error(error))

How the default asset resolution works

Anna's builtin asset resolution works by finding the physical file that can be associated with each asset URL. Where asset URLs can be absolute like /my-assets/file.ext or relative like my-assets/file.ext or ../my-assets/file.ext (remote URLs are ignored).

Physical files are found by traversing up the directory hierarchy starting with the directory of the source file and searching for the first matching file by removing path segments from the left side of the URL. Typically, the first matching file has the longest path (i.e. the most specific file).

If the source file src/components/Badge/index.js contained the following asset URL Badge/default-badge.svg then the following locations will be visited to find the asset file associated with the asset URL.

src/components/Badge/Badge/default-badge.svg
src/components/Badge/default-badge.svg
src/components/Badge/default-badge.svg
src/components/default-badge.svg
src/Badge/default-badge.svg
src/default-badge.svg
Badge/default-badge.svg
default-badge.svg

and so on up to the current working directory (i.e. project root). These locations are the same regardless if the asset URL is absolute (/Badge/default-badge.svg) or relative (Badge/default-badge.svg). However, if the asset URL is relative and contains ../ in the URL then it will change the locations visited due to path normalization, and the file with the longest path may not always be chosen.

For example, had the asset URL been ../Badge/default-badge.svg then the following locations would have been visited.

src/components/Badge/default-badge.svg
src/components/Badge/Badge/default-badge.svg
src/components/Badge/default-badge.svg
src/Badge/default-badge.svg
src/components/Badge/default-badge.svg
src/components/default-badge.svg
Badge/default-badge.svg
src/Badge/default-badge.svg
src/default-badge.svg
../Badge/default-badge.svg
Badge/default-badge.svg
default-badge.svg

Because of this path normalization and the affect it has on the resolution algorithm, it's not recommended that ../ be used in your asset URLs unless you are fully aware of the side effects (i.e. you could unintentionally match asset files in locations further up the directory hierarchy).

Relative asset URLs can also lead to unstable URLs in the production code, that is the URLs being used by the code will need to be translated/compiled to update their pathing. It's better to always use absolute URLs so that the code is expecting assets to load from the web server root. This is far easier to handle at the server level via custom routing. The only time using relative or arbitrary URLs makes sense is if you're not using the URL directly or in your code you translate the URL before use.

Example:

// Normal usage as usual, but we call our own asset() function.

fetch(asset('badge.svg')).then(...)

// In our code we deliberately translate URLs that Anna picks up into
// production URLs.
function asset (url) {
  // TODO: Do something with the URL, perhaps
  // do a lookup in an embed table or just prepend a path to the URL.
}

This asset file resolution algorithm is the same regardless of what source file the asset URL is parsed from.

API

Coming soon!