![]() |
VOOZH | about |
dotnet add package Acornima --version 1.6.2
NuGet\Install-Package Acornima -Version 1.6.2
<PackageReference Include="Acornima" Version="1.6.2" />
<PackageVersion Include="Acornima" Version="1.6.2" />Directory.Packages.props
<PackageReference Include="Acornima" />Project file
paket add Acornima --version 1.6.2
#r "nuget: Acornima, 1.6.2"
#:package Acornima@1.6.2
#addin nuget:?package=Acornima&version=1.6.2Install as a Cake Addin
#tool nuget:?package=Acornima&version=1.6.2Install as a Cake Tool
👁 GitHub Actions Workflow Status
👁 NuGet Release
👁 Feedz Version
👁 Donate
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.
StackOverflowException using the same approach as Roslyn.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
using Acornima;
var parser = new Parser();
Or, if you want to tweak the available settings:
var parser = new Parser(new ParserOptions { /* ... */ });
var ast = parser.ParseScript("console.log('Hello world!')");
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.)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.
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!</>");
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]
Projects using Esprima.NET can be converted to Acornima relatively easily as the public API of the two libraries are very similar. (A pretty good proof of this statement is this PR, which migrates Jint to Acornima.)
The most notable changes to keep in mind with regard to migration are the following:
ParserOptions.RegExpParseMode property has been changed to RegExpParseMode.Validate.ParserOptions.RegexTimeout property has been changed to 5 seconds.ParserOptions.Tolerant property has been changed to false.Location struct has been renamed to SourceLocation.TokenType and CommentType enums have been renamed named to TokenKind and CommentKind, respectively. Also, some of the member names have been changed.Token and Comment structs have been completely reworked. The SyntaxToken and SyntaxComment classes have been removed.SyntaxElement class has been removed, that is, the Node class has become the root of the AST node type hierarchy. (This also means that tokens and comments are not attached to the root nodes of the AST. You can obtain those via the ParserOptions.OnToken and ParserOptions.OnComment callbacks).Nodes enum has been renamed to NodeType.Node.AssociatedData property has been renamed to UserData.AssignmentOperator, BinaryOperator and UnaryOperator enums have been merged into a single enum named Operator. Also, some of the member names have been changed.Literal node class has been changed to only provide an object? Value { get; } property for accessing literal value. There are sealed subclasses for the different kinds of literals. Use those to access literal values in a type-safe (and more efficient) manner.Property node class has been made abstract and two sealed subclasses have been introduced: AssignmentProperty and ObjectProperty (for representing properties of object destructuring patterns and object literals, respectively). Also, the VisitProperty method has been replaced with VisitAssignmentProperty and VisitObjectProperty in visitors.BlockStatement node class. Two new sealed subclasses have been introduced: FunctionBody and NestedBlockStatement (for representing bodies of function expressions/declarations and actual block statements that occurs within function bodies, respectively). Also, to conform to the ESTree spec, StaticBlock has been changed to be a subclass of BlockStatement. The VisitBlockStatement method has been kept in visitors, but only NestedBlockStatement is dispatched to it. The other two subclasses has dedicated visitation methods (VisitFunctionBody and VisitStaticBlock).ClassElement node base class has been replaced with the IClassElement interface.Strict property of function expression/declaration node classes has been moved to FunctionBody.JsxExpression node class has been renamed to JsxNode.JsxElement node class has been renamed to JsxElementOrFragment and two sealed subclasses have been introduced: JsxElement and JsxFragment.ParserException class has been renamed to ParseErrorException and been made abstract. Two concrete subclasses (SyntaxErrorException and RegExpConversionError) have been introduced to indicate different kinds of errors that can occur during parsing.ParseErrorException class has been changed. The reported messages are translatable text resources, so it is not recommended to rely on them to determine the reason of the error. For such purposes, you can use the ParseErrorException.Error.Code property.ParseErrorException.Column property has been changed to store zero-based indices. (The exception message still includes one-based column indices though.)BenchmarkDotNet v0.15.6, Windows 10
AMD Ryzen 7 7735HS with Radeon Graphics 3.20GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 10.0.201
[Host] : .NET 10.0.5 (10.0.5, 10.0.526.15411), X64 RyuJIT x86-64-v3
.NET 10.0 : .NET 10.0.5 (10.0.5, 10.0.526.15411), X64 RyuJIT x86-64-v3
Job=.NET 10.0 Runtime=.NET 10.0 Toolchain=net10.0
IterationCount=15 LaunchCount=2 WarmupCount=10
| Method | FileName | Mean | Allocated |
|---|---|---|---|
| Acornima v1.4.0 | angular-1.2.5 | 6,536.1 μs | 3970.92 KB |
| Esprima v3.0.5 | angular-1.2.5 | 6,535.1 μs | 3828.1 KB |
| Acornima v1.4.0 | angular-1.7.9 | 14,729.4 μs | 6719.11 KB |
| Esprima v3.0.5 | angular-1.7.9 | 14,329.3 μs | 6575.47 KB |
| Acornima v1.4.0 | backbone-1.1.0 | 806.1 μs | 628.3 KB |
| Esprima v3.0.5 | backbone-1.1.0 | 824.9 μs | 613.88 KB |
| Acornima v1.4.0 | jquery-1.9.1 | 4,784.7 μs | 3263.86 KB |
| Esprima v3.0.5 | jquery-1.9.1 | 5,167.4 μs | 3305.23 KB |
| Acornima v1.4.0 | jquery.mobile-1.4.2 | 8,588.6 μs | 5443.43 KB |
| Esprima v3.0.5 | jquery.mobile-1.4.2 | 8,190.9 μs | 5428.44 KB |
| Acornima v1.4.0 | mootools-1.4.5 | 3,923.1 μs | 2750.82 KB |
| Esprima v3.0.5 | mootools-1.4.5 | 4,089.0 μs | 2777.83 KB |
| Acornima v1.4.0 | underscore-1.5.2 | 683.6 μs | 528.92 KB |
| Esprima v3.0.5 | underscore-1.5.2 | 702.5 μs | 539.41 KB |
| Acornima v1.4.0 | yui-3.12.0 | 3,618.3 μs | 2607.91 KB |
| Esprima v3.0.5 | yui-3.12.0 | 3,674.8 μs | 2585.77 KB |
The parser can be configured to convert JS regular expression literals to .NET Regex instances (see ParserOptions.RegExpParseMode).
However, because of the fundamental differences between the JS and .NET regex engines, in many cases this conversion can't be done perfectly (or, in some cases, at all):
RegExpParseResult object's ActualRegexGroupCount property.$group is valid in JS but invalid in .NET. So, as a workaround, the converter encodes the problematic group names to names that are valid in .NET and probably won't collide with other group names present in the pattern. For example, $group is encoded like __utf8_2467726F7570. The original group names can be obtained using the returned RegExpParseResult object's GetRegexGroupName method./((a+)(\1) ?)+/ may not produce the exact same captures. RegexOptions.ECMAScript is supposed to cover this, however even the MSDN example doesn't produce the same matches. (As a side note, RegexOptions.ECMAScript is kind of a false promise, it can't even get some basic cases right by itself.)/((a+)?(b+)?(c))*/ may produce different captures for the groups. (JS has an overwrite behavior while .NET doesn't).\1(\w) differently than JS and it's not possible to convert this kind of patterns reliably. (The converter could make some patterns work by rewriting them to something like (?:)(\w) but there are cases where even this wouldn't work.)/a?/u will cause this issue when the input string contains astral Unicode chars. There is no out-of-the-box workaround for this issue but it can be mitigated somewhat using a bit of "post-processing", i.e., by filtering out the false positive matches after evaluation like it's done here. Probably there is no way to improve this situation until .NET adds the option to treat the input string as Unicode code points.To sum it up, legacy pattern conversion is pretty solid apart from the minor issues listed above. However, support for unicode mode (flag u) patterns is partial and quirky, while conversion of the upcoming unicode sets mode (flag v) will be next to impossible - until the .NET regex engine gets some improved Unicode support.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 is compatible. |
| .NET Framework | net461 net461 was computed. net462 net462 is compatible. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on Acornima:
| Package | Downloads |
|---|---|
|
Jint
Javascript interpreter for .NET. |
|
|
SourceMapTools
A C# library that allows for the consumption of source maps and the deminification of JavaScript stack traces. |
|
|
Karambolo.AspNetCore.Bundling.EcmaScript
ES6 (ECMAScript 2015) module bundling features for the Karambolo.AspNetCore.Bundling library. |
|
|
Acornima.Extras
Additional features and utilities for the Acornima package. |
|
|
Js2IL.Core
Reusable js2il compiler library for embedding JavaScript-to-.NET compilation in custom .NET tools and hosts. |
Showing the top 3 popular GitHub repositories that depend on Acornima:
| Repository | Stars |
|---|---|
|
sebastienros/jint
Javascript Interpreter for .NET
|
|
|
ape-byte/DouyinBarrageGrab
基于系统代理的抖音弹幕wss抓取程序,能够获取所有数据来源,包括chrome,抖音直播伴侣等,可进行进程过滤
|
|
|
Altinn/altinn-studio
Next generation open source Altinn platform and applications.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 1.6.2 | 83,945 | 5/16/2026 |
| 1.6.1 | 38,737 | 4/25/2026 |
| 1.6.0 | 1,135 | 4/15/2026 |
| 1.5.0 | 488 | 4/13/2026 |
| 1.4.0 | 200,251 | 4/10/2026 |
| 1.3.2 | 26,736 | 4/1/2026 |
| 1.3.1 | 102,449 | 3/13/2026 |
| 1.3.0 | 38,401 | 3/10/2026 |
| 1.2.1 | 1,266 | 3/2/2026 |
| 1.2.0 | 2,256,631 | 7/12/2025 |
| 1.1.1 | 1,817,844 | 1/1/2025 |
| 1.1.0 | 1,669,382 | 6/22/2024 |
| 1.0.0 | 8,868 | 4/7/2024 |
| 0.9.3 | 939 | 4/3/2024 |
| 0.9.2 | 918 | 3/31/2024 |
| 0.9.1 | 960 | 3/29/2024 |
| 0.9.0 | 3,533 | 3/26/2024 |