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

ast-matcher

v1.2.0

Published

Create pattern based AST matcher function

Downloads

9,555

Readme

ast-matcher CI

Create pattern based AST matcher function. So you don't need to be an AST master in order to do static code analysis for JavaScript.

npm install ast-matcher

This tool can be used in Node.js or browser. You may need some polyfill for missing JavaScript features in very old browsers.

First, choose a parser

Beware ast-matcher doesn't install a parser for you. You need to manually install one.

We support any parser compatible with ESTree spec. Here are some popular ones:

Take esprima for example, you need to use setParser to hook it up for ast-matcher.

const esprima = require('esprima');
const astMatcher = require('ast-matcher');
// with es6, import astMatcher, { depFinder } from 'ast-matcher';

astMatcher.setParser(esprima.parse);
// or pass options to esprima
astMatcher.setParser(function(contents) {
  return esprima.parse(contents, {jsx: true});
});

Beware @babel/parser needs estree plugin

const parser = require('@babel/parser');
const astMatcher = require('ast-matcher');

astMatcher.setParser(function(contents) {
  return parser.parse(contents, {
    // ... other options
    plugins: [
      // ... other plugins
      'estree'
    ]
  });
});

For TypeScript user, use:

import * as astMatcher from 'ast-matcher';`
let { depFinder } = astMatcher;

API doc for two main functions: astMatcher and depFinder.

astMatcher

Pattern matching using AST on JavaScript source code.

const matcher = astMatcher('__any.method(__str_foo, [__arr_opts])')
matcher('au.method("a", ["b", "c"]); jq.method("d", ["e"])');
// => [
//      {match: {foo: "a", opts: ["b", "c"]}, node: <CallExpression node> }
//      {match: {foo: "d", opts: ["e"]}, node: <CallExpression node> }
//    ]

astMatcher takes a pattern to be matched. The pattern can only be single statement, not multiple statements. Generates a function that:

  • takes source code string (or estree syntax tree) as input,
  • produces matched result or undefined.

Support following match terms in pattern:

  • __any matches any single node, but no extract
  • __anl matches array of nodes, but no extract
  • __str matches string literal, but no extract
  • __arr matches array of partial string literals, but no extract
  • __any_aName matches single node, return {aName: node}
  • __anl_aName matches array of nodes, return {aName: array_of_nodes}
  • __str_aName matches string literal, return {aName: value}
  • __arr_aName matches array, extract string literals, return {aName: [values]}

__arr, and __arr_aName can match partial string array. [foo, "foo", "bar", lorem] => ["foo", "bar"]

use method(__anl) or method(__arr_a) to match method(a, "b");

use method([__anl]) or method([__arr_a]) to match method([a, "b"]);

depFinder

Dependency analysis for dummies, this is a high level api to simplify the usage of astMatcher.

const depFinder = astMatcher.depFinder;
const finder = depFinder('a(__dep)', '__any.globalResources([__deps])');
finder('a("a"); a("b"); config.globalResources(["./c", "./d"])');
// => ['a', 'b', './c', './d']

depFinder takes multiple patterns to match, instead of using __str_/__arr, use __dep and __deps to match string and partial string array. Generates a function that:

  • takes source code string (or estree syntax tree) as input,
  • produces an array of string matched, or empty array.

Examples

1. find AMD dependencies

Beware AMD module could be wrapped commonjs module, you need to remove ['require', 'exports', 'module'] from the result.

const amdFind = depFinder(
  'define([__deps], __any)', // anonymous module
  'define(__str, [__deps], __any)' // named module
);
const deps = amdFind(amdJsFileContent_or_parsed_ast_tree);

2. find CommonJS dependencies

const cjsFind = depFinder('require(__dep)');
const deps = cjsFind(cjsJsFileContent_or_parsed_ast_tree);

3. match if statement

const matcher = astMatcher('if ( __any_condition ) { __anl_body }');
const m = matcher(code_or_parsed_ast_tree);
// => [
//   {
//     match: { condition: a_node, body: array_of_nodes },
//     node: if_statement_node
//   },
//   ...
// ]

4. match if-else statement

const matcher = astMatcher('if ( __any_condition ) { __anl_ifBody } else { __anl_elseBody }');
const m = matcher(code_or_parsed_ast_tree);
// => [
//   {
//     match: { condition: a_node, ifBody: array_of_nodes, elseBody: array_of_nodes },
//     node: if_else_statement_node
//   },
//   ...
// ]

5. find Aurelia framework's PLATFORM.moduleName() dependencies

const auJsDepFinder = depFinder(
  'PLATFORM.moduleName(__dep)',
  '__any.PLATFORM.moduleName(__dep)',
  'PLATFORM.moduleName(__dep, __any)',
  '__any.PLATFORM.moduleName(__dep, __any)'
);
const deps = auJsDepFinder(auCode_or_parsed_ast_tree);