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 🙏

© 2025 – Pkg Stats / Ryan Hefner

cayce-plugin-apex

v1.0.20

Published

This package contains rules for the cayce static analysis tool that pertain to the Apex programming language. The rules have been gathered from a small group of sources (personal experience and PMD's existing ruleset for starters.)

Readme

cayce-plugin-apex

This package contains rules for the cayce static analysis tool that pertain to the Apex programming language. The rules have been gathered from a small group of sources (personal experience and PMD's existing ruleset for starters.)

Please see the cayce-core repository, or take a look at the GitHub org CayceCodes.

Tree-Sitter Queries

Generally speaking, Cayce relies on tree-sitter queries in order to identify source that may or may not need remediation. Tree-sitter is a concrete syntax tree alternative to the more common abstract syntax tree that is provided by parser generators such as ANTLR4.

Tree-sitter's queries are constructed as s-expressions, similar to languages like Lisp. Identifiers are sourrounded by parenthesis and the heirarchy is defined by the nesting of those containers. The identifiers used to pinpoin specific nodes in the source tree are not specific to tree-sitter. Those node type names (and any tokens used to parse the source) are defined in the grammar that was created to support a specific language, such as Apex.

Consider the following query:

(variable_declarator name: (identifier) @variableName (#match? @variableName "[0-9]"))`

This query will retrieve all variable names that contain numbers. If you require a rule that flags variable names that contain numbers, this would be your query in the custom ruke you created (or in an existing rule, as the case may be.) variable_declarator is the node type name, or 'grammar type' for the inner declaration of a variable. This excludes the data type of the variable, as that is included in the parent local_variable_declaration grammar type.

So, if that query is run against the following source:

Integer foo1 = 1;

It would return the variable name's syntax node, foo1.

That query also highlights some of the features built in to the query language:

  • Names (or 'capture names'): These are variables you assign to nodes that you want to capture for further inspection or reporting. In this query, @variableName is a capture name.
  • Predecates: #match? is an example of a predicate. That particular one is for matching against a regular expression. You can prefix any predicate with not- as in #not-match? to do a negative test. Another predicate of note is #eq? which tests for an exact match (or no match if it's written as #not-eq?). Predacates are written as follows:
(#predicate-name? @captureName "what_to_test_against")

That predicate statement should come directly after the capture name is declared and assigned to a given node...in this case, we assign it to the identifier node that contains the name. name: is where we distinguish this identifier as being the variable name as opposed to other nodes in our query's heirarchy wuth the same grammar name.

For further reference, check out the tree-sitter query documentation, and it is prudent to use a tree-sitter playground (usually created for every language with a tree sitter module) to validated your queries.

Rule Format / Custom Rule Authoring

Since this is the first plugin for the Cayce tool, it is a good example for those looking to write their own language plugins or rules for existing languages.

Custom Rules

Cayce rules all inherit from ScanRule in the cayce-types package. It provides a blueprint/functionality for annotatiuns and tree-sitter query execution.

Annotations

Annotations are the primary method used to configure Cayce rules. If implemented well, they can provide most (if not all) the functionality that a rule needs to function. The following is a list of the current set of annotations, their meanings, and any further information that might help you.

(WIP)

ScanRule

All rules also share a common superclass, ScanRule. This abstract class provides not only the framework for the annotations listed above, it provides the primary method used to filter through the results of a tree sitter query. The name of this method is validate and it is the most important part of a rule. It's also important to note that the plugin is the only component that cares about a specific language. The specific language implementation is irrelevant to the cli, core classes, and types. This means that when creating a new language module, the language's tree-sitter "adapter" package reference needs to live in the language's plugin class.

While building the tool, special attention was paid to the ability to 'analyze outside the box.' The validate method doesn't limit you to using tree-sitter specific (or even language specific) nodes. You can use regular expressions, plain old brute force parsing, even leverage an AST-approach via ANTLR's TypeScript support. The goal was to make sure there is a way to get to the inspections that matter without barriers, and trust you to implement things in a safe and sane manner.

Unit Testing

Cayce plugins follow a testing ethod similar to PMD: the tests themselves ccontain little code, and they rely on data to drive any assertions that need to be made in order to call a unit test passed. The following is an example of two unit test definitions:

 {
       name: 'VariableNamesTooShortPositiveUnitTest',
       enabled: true,
       ruleInstance: new ShortVariableNames(),
       expectedResults: [
           'variable_declarator',
           'variable_declarator',
           'formal_parameter',
           'variable_declarator'],
       sourceToTest: `
       public class TestClass{
           public TestClass(){
               Integer a = 0;
               String b = '';
           }
 
           public boolean validate(String s){
               String n = s.reverse();
 
               return (n == 'foo');
           }
       }
       `
  }