SkillAgentSearch skills...

Acornima

Acornima is a standard-compliant JavaScript parser for .NET. It is a fork of Esprima.NET combined with the .NET port of the acornjs parser.

Install / Use

/learn @adams85/Acornima
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

GitHub Actions Workflow Status NuGet Release Feedz Version Donate

Stand With Ukraine

Acorn + Esprima = Acornima

This project is a crossbreeding of the acornjs and the Esprima.NET parsers, with the intention of creating an even more complete and performant ECMAScript (a.k.a JavaScript) parser library for .NET by combining the best bits of those.

It should also be mentioned that there is an earlier .NET port of acornjs, AcornSharp, which though is unmaintained for a long time, served as a good starting point. Had it not been for AcornSharp, this project would probably have never started.

Here is how this Frankenstein's monster looks like:

  • The tokenizer is mostly a direct translation of the acornjs tokenizer to C# (with many bigger and smaller performance improvements, partly inspired by Esprima.NET) - apart from the regex validation/conversion logic, which has been borrowed from Esprima.NET.
  • The parser is ~99% acornjs (also with a bunch of minor improvements) and ~1% Esprima.NET (strict mode detection, public API). It is also worth mentioning that the error reporting has been changed to use the error messages of V8.
  • It includes protection against the non-catchable StackOverflowException using the same approach as Roslyn.
  • Both parent projects follow the ESTree specification, so does Acornima. The actual AST implementation is based on that of Esprima.NET, with further minor improvements to the class hierarchy that bring it even closer to the spec and allow encoding a bit more information.
  • The built-in AST visitors and additional utility features stems from Esprima.NET as well.

And what good comes out of this mix?

  • A parser that matches the performance of Esprima.NET while doing more: it also passes the complete Test262 test suite for ECMAScript 2023.
  • It is also more economic with regard to stack usage, so it can parse ~2x deeper structures.
  • More options for fine-tuning parsing.
  • A standalone tokenizer which can deal with most of the ambiguities of the JavaScript grammar (thanks to the clever context tracking solution implemented by acornjs).
  • The parser tracks variable scopes to detect variable redeclarations. As of v1.1.0, it's able to expose the collected scope information to the consumer (see also this PR or this other example of usage).

Getting started

1. Install the package from NuGet

dotnet add package Acornima

Or, if you want to use additional features like JSX parsing, JavaScript generation from AST or AST to JSON conversion:

dotnet add package Acornima.Extras

2. Import the Acornima namespace in your application

using Acornima;

3. Create a parser instance

var parser = new Parser();

Or, if you want to tweak the available settings:

var parser = new Parser(new ParserOptions { /* ... */ });

4. Use the parser instance to parse your JavaScript code

var ast = parser.ParseScript("console.log('Hello world!')");

AST

Node [x]
 ├─AssignmentPattern : IDestructuringPatternElement [v,s]
 ├─CatchClause [v,s]
 ├─ClassBody [v,s]
 ├─ClassProperty : IClassElement, IProperty
 │  ├─AccessorProperty : IClassElement, IProperty [v,s]
 │  ├─MethodDefinition : IClassElement, IProperty [v,s]
 │  └─PropertyDefinition : IClassElement, IProperty [v,s]
 ├─Decorator [v,s]
 ├─DestructuringPattern : IDestructuringPatternElement
 │  ├─ArrayPattern : IDestructuringPatternElement [v,s]
 │  └─ObjectPattern : IDestructuringPatternElement [v,s]
 ├─ImportAttribute [v,s]
 ├─ModuleSpecifier
 │  ├─ExportSpecifier [v,s]
 │  └─ImportDeclarationSpecifier
 │     ├─ImportDefaultSpecifier [v,s]
 │     ├─ImportNamespaceSpecifier [v,s]
 │     └─ImportSpecifier [v,s]
 ├─Program : IHoistingScope [v]
 │  ├─Module : IHoistingScope [s,t=Program]
 │  └─Script : IHoistingScope [s,t=Program]
 ├─Property : IProperty
 │  ├─AssignmentProperty : IProperty [v,s,t=Property]
 │  └─ObjectProperty : IProperty [v,s,t=Property]
 ├─RestElement : IDestructuringPatternElement [v,s]
 ├─StatementOrExpression
 │  ├─Expression [x]
 │  │  ├─ArrayExpression [v,s]
 │  │  ├─ArrowFunctionExpression : IFunction [v,s]
 │  │  ├─AssignmentExpression [v,s]
 │  │  ├─AwaitExpression [v,s]
 │  │  ├─BinaryExpression [v]
 │  │  │  ├─LogicalExpression [s]
 │  │  │  └─NonLogicalBinaryExpression [s,t=BinaryExpression]
 │  │  ├─CallExpression : IChainElement [v,s]
 │  │  ├─ChainExpression [v,s]
 │  │  ├─ClassExpression : IClass [v,s]
 │  │  ├─ConditionalExpression [v,s]
 │  │  ├─FunctionExpression : IFunction [v,s]
 │  │  ├─Identifier : IDestructuringPatternElement [v,s]
 │  │  ├─ImportExpression [v,s]
 │  │  ├─Literal [v]
 │  │  │  ├─BigIntLiteral [s,t=Literal]
 │  │  │  ├─BooleanLiteral [s,t=Literal]
 │  │  │  ├─NullLiteral [s,t=Literal]
 │  │  │  ├─NumericLiteral [s,t=Literal]
 │  │  │  ├─RegExpLiteral [s,t=Literal]
 │  │  │  └─StringLiteral [s,t=Literal]
 │  │  ├─MemberExpression : IChainElement, IDestructuringPatternElement [v,s]
 │  │  ├─MetaProperty [v,s]
 │  │  ├─NewExpression [v,s]
 │  │  ├─ObjectExpression [v,s]
 │  │  ├─ParenthesizedExpression [v,s]
 │  │  ├─PrivateIdentifier [v,s]
 │  │  ├─SequenceExpression [v,s]
 │  │  ├─SpreadElement [v,s]
 │  │  ├─Super [v,s]
 │  │  ├─TaggedTemplateExpression [v,s]
 │  │  ├─TemplateLiteral [v,s]
 │  │  ├─ThisExpression [v,s]
 │  │  ├─UnaryExpression [v]
 │  │  │  ├─NonUpdateUnaryExpression [s,t=UnaryExpression]
 │  │  │  └─UpdateExpression [s]
 │  │  └─YieldExpression [v,s]
 │  └─Statement [x]
 │     ├─BlockStatement [v]
 │     │  ├─FunctionBody : IHoistingScope [v,s,t=BlockStatement]
 │     │  ├─NestedBlockStatement [s,t=BlockStatement]
 │     │  └─StaticBlock : IClassElement, IHoistingScope [v,s]
 │     ├─BreakStatement [v,s]
 │     ├─ContinueStatement [v,s]
 │     ├─DebuggerStatement [v,s]
 │     ├─Declaration [x]
 │     │  ├─ClassDeclaration : IClass [v,s]
 │     │  ├─FunctionDeclaration : IFunction [v,s]
 │     │  ├─ImportOrExportDeclaration
 │     │  │  ├─ExportDeclaration
 │     │  │  │  ├─ExportAllDeclaration [v,s]
 │     │  │  │  ├─ExportDefaultDeclaration [v,s]
 │     │  │  │  └─ExportNamedDeclaration [v,s]
 │     │  │  └─ImportDeclaration [v,s]
 │     │  └─VariableDeclaration [v,s]
 │     ├─DoWhileStatement [v,s]
 │     ├─EmptyStatement [v,s]
 │     ├─ExpressionStatement [v]
 │     │  ├─Directive [s,t=ExpressionStatement]
 │     │  └─NonSpecialExpressionStatement [s,t=ExpressionStatement]
 │     ├─ForInStatement [v,s]
 │     ├─ForOfStatement [v,s]
 │     ├─ForStatement [v,s]
 │     ├─IfStatement [v,s]
 │     ├─LabeledStatement [v,s]
 │     ├─ReturnStatement [v,s]
 │     ├─SwitchStatement [v,s]
 │     ├─ThrowStatement [v,s]
 │     ├─TryStatement [v,s]
 │     ├─WhileStatement [v,s]
 │     └─WithStatement [v,s]
 ├─SwitchCase [v,s]
 ├─TemplateElement [v,s]
 └─VariableDeclarator [v,s]

Legend:

  • v - A visitation method is generated in the visitors for the node type.
  • s - The node class is sealed. (It's beneficial to check for sealed types when possible.)
  • t - The node type (the value of the Node.Type property) as specified by ESTree (shown only if it differs from the name of the node class).
  • x - The node class can be subclassed. (The AST provides some limited extensibility for special use cases.)

JSX

The library also supports the syntax extension JSX. However, mostly for performance reasons, the related functionality is separated from the core parser: it is available in the Acornima.Extras package, in the Acornima.Jsx namespace.

Installation & usage

After installing the Acornima.Extras package as described in the Getting started section, you can parse JSX code like this:

using Acornima.Jsx;

var parser = new JsxParser(new JsxParserOptions { /* ... */ });

var ast = parser.ParseScript("<>Hello world!</>");

AST

Node [x]
 └─StatementOrExpression
    └─Expression [x]
       └─JsxNode [x]
          ├─JsxAttributeLike
          │  ├─JsxAttribute [v,s]
          │  └─JsxSpreadAttribute [v,s]
          ├─JsxClosingTag
          │  ├─JsxClosingElement [v,s]
          │  └─JsxClosingFragment [v,s]
          ├─JsxElementOrFragment
          │  ├─JsxElement [v,s]
          │  └─JsxFragment [v,s]
          ├─JsxEmptyExpression [v,s]
          ├─JsxExpressionContainer [v,s]
          ├─JsxName
          │  ├─JsxIdentifier [v,s]
          │  ├─JsxMemberExpression [v,s]
          │  └─JsxNamespacedName [v,s]
          ├─JsxOpeningTag
          │  ├─JsxOpeningElement [v,s]
          │  └─JsxOpeningFragment [v,s]
          └─JsxText [v,s]

Migration from Esprima.NET

Projects using Esprima.NET can be converted to Acornima relativel

View on GitHub
GitHub Stars44
CategoryDevelopment
Updated3d ago
Forks4

Languages

C#

Security Score

90/100

Audited on Mar 29, 2026

No findings