ECMAScript Compatibility
Relevant source files
The following files were used as context for generating this wiki page:
- README.md
- Test Suite Runner/Test Suite Files/harness/helper.js
- Test Suite Runner/Kangax/compat-table.txt
- Test Suite Runner/Test Suite Files/harness/sta.js
- Test Suite Runner/Test Suite Files/harness/sections.js
- Test Suite Runner/Kangax/compat-table.json
- Unit Tests/Real-world/RealWorldTests.cs
- Jurassic/Library/GlobalObject.cs
- Jurassic/Library/Reflect/Reflect.g.cs
- Jurassic/Library/RegExp/RegExpInstance.g.cs
- Test Suite Runner/Test Suite Files/harness/gs.js
- Unit Tests/Core/DocumentationSamples.cs
Jurassic is a .NET implementation of the ECMAScript language and runtime. A primary goal of the project is to provide a highly standards-compliant implementation of JavaScript. The engine fully supports ECMAScript 3 and ECMAScript 5 (including strict mode) and has partial, in-progress support for ECMAScript 6.
Compatibility is validated through an extensive suite of over five thousand unit tests and by running real-world JavaScript libraries. The project utilizes established test suites like the Kangax compatibility table and test262 to ensure adherence to the ECMAScript specification.
Sources: README.md:5-7, README.md:11
ECMAScript 6 Status
Support for ECMAScript 6 is under active development. The following table provides a snapshot of the feature compatibility status.
| Feature | Status |
|---|---|
| Optimisation | |
| proper tail calls (tail call optimisation) | :x: |
| Syntax | |
| default function parameters | 4/7 |
| rest parameters | :x: |
| spread syntax for iterable objects | :x: |
| object literal extensions | :white_check_mark: 6/6 |
| for..of loops | 6/9 |
| octal and binary literals | :white_check_mark: 4/4 |
| template literals | 6/7 |
| RegExp "y" and "u" flags | :x: |
| destructuring, declarations | :x: |
| destructuring, assignment | :x: |
| destructuring, parameters | :x: |
| Unicode code point escapes | :white_check_mark: 4/4 |
| new.target | :white_check_mark: 2/2 |
| Bindings | |
| const | :white_check_mark: 18/18 |
| let | 14/16 |
| block-level function declaration[18] | :x: |
| Functions | |
| arrow functions | :x: |
| class | :white_check_mark: 24/24 |
| super | :white_check_mark: 8/8 |
| generators | :x: |
| Built-ins | |
| typed arrays | 45/46 |
| Map | 18/19 |
| Set | 18/19 |
| WeakMap | 11/12 |
| WeakSet | 10/11 |
| Proxy [25] | 33/34 |
| Reflect [26] | 18/20 |
| Promise | 4/8 |
| Symbol | :white_check_mark: 12/12 |
| well-known symbols[27] | 23/26 |
| Built-in extensions | |
| Object static methods | :white_check_mark: 4/4 |
| function "name" property | 10/17 |
| String static methods | :white_check_mark: 2/2 |
| String.prototype methods | :white_check_mark: 10/10 |
| RegExp.prototype properties | :white_check_mark: 6/6 |
| Array static methods | 8/11 |
| Array.prototype methods | :white_check_mark: 10/10 |
| Number properties | :white_check_mark: 9/9 |
| Math methods | :white_check_mark: 17/17 |
| Date.prototype[Symbol.toPrimitive] | :white_check_mark: 1/1 |
| Subclassing | |
| Array is subclassable | 9/11 |
| RegExp is subclassable | :white_check_mark: 4/4 |
| Function is subclassable | 4/6 |
| Promise is subclassable | :x: |
| miscellaneous subclassables | :x: |
| Misc | |
| prototype of bound functions | 1/5 |
| Proxy, internal 'get' calls | 19/36 |
| Proxy, internal 'set' calls | 7/11 |
| Proxy, internal 'defineProperty' calls | :x: |
| Proxy, internal 'deleteProperty' calls | :x: |
| Proxy, internal 'getOwnPropertyDescriptor' calls | 2/4 |
| Proxy, internal 'ownKeys' calls | :white_check_mark: 3/3 |
| Object static methods accept primitives | :white_check_mark: 10/10 |
| &s_p;own property order | 5/7 |
| Updated identifier syntax | 1/3 |
| miscellaneous | 8/9 |
| Annex b | |
| non-strict function semantics[35] | 2/3 |
| __proto__ in object literals [36] | :x: |
| Object.prototype.__proto__ | 1/6 |
| String.prototype HTML methods | :white_check_mark: 3/3 |
| RegExp.prototype.compile | 1/2 |
| RegExp syntax extensions | 4/8 |
| HTML-style comments | :x: |
Sources: README.md:20-155
Testing and Validation
Jurassic employs a multi-faceted approach to ensure ECMAScript compatibility, combining standardized test suites with real-world library execution.
Kangax ES6 Compatibility Suite
The project uses tests from the Kangax compatibility table to validate ES6 features. These tests are stored in a JSON format and are executed by the test runner.
Sources: Test Suite Runner/Kangax/compat-table.txt
The process to generate the test data is manual, involving a script run in the browser console on the Kangax compatibility table website.
The following diagram illustrates the workflow for generating the compat-table.json file.
Each test case in compat-table.json is an object containing the feature name, group, details, and the JavaScript code to execute.
// Example from Test Suite Runner/Kangax/compat-table.json
{
"name":"const",
"group":"Bindings",
"detail":"basic support",
"script":"\nconst foo = 123;\nreturn (foo === 123);\n "
}
Sources: Test Suite Runner/Kangax/compat-table.json:478-482
Test262 Harness
The project includes a test harness for running test suites like test262. This harness is responsible for executing tests, tracking results, and presenting them in a structured way.
The main components of the harness are:
- Presenter: Manages the test execution flow and updates the user interface with results.
- Section: Represents a section of the ECMAScript specification, organizing tests hierarchically.
- Test Helpers: A collection of utility functions for assertions and environment checks.
The diagram below shows the relationship between the main harness components.
Test Execution Flow
When a test is run, the Presenter object orchestrates the process of recording and displaying the result.
The following sequence diagram shows how a test result is processed.
Test Case Validation
The harness includes a validator for handling both positive and negative test cases. For negative tests, it checks if an exception was thrown and if the error message matches the expected pattern.
Helper Functions
A rich set of helper functions, originally adapted from the Sputnik test framework, is available for writing detailed assertions. These functions allow for precise verification of object property attributes.
| Function | Description |
|---|---|
dataPropertyAttributesAreCorrect | Verifies all attributes of a data property (value, writable, enumerable, configurable). |
accessorPropertyAttributesAreCorrect | Verifies all attributes of an accessor property (get, set, enumerable, configurable). |
fnSupportsStrict | Checks if the engine supports strict mode. |
fnExists | Checks if the given arguments are functions. |
Sources: Test Suite Runner/Test Suite Files/harness/sta.js:107-220, Test Suite Runner/Test Suite Files/harness/sta.js:97-105, Test Suite Runner/Test Suite Files/harness/sta.js:80-85
Real-World Library Testing
To ensure practical compatibility, Jurassic is tested against several popular, real-world JavaScript libraries. These tests are defined in C# and execute the libraries within the Jurassic engine, asserting correct behavior.
Libraries used for testing include:
- Showdown (Markdown processor)
- CoffeeScript (Compiler)
- sprintf.js
- Various cryptography libraries (MD5, SHA1, SHA256)
- LZW compression
- jsbn (RSA encryption)
- BigNumber.js
Sources: Unit Tests/Real-world/RealWorldTests.cs
The following C# code snippet demonstrates how the Showdown library is tested.
// From: Unit Tests/Real-world/RealWorldTests.cs
[TestMethod]
public void Showdown()
{
// See http://attacklab.net/showdown/
var engine = new ScriptEngine();
engine.ExecuteFile(@"../../../Real-world/Files/showdown.js");
engine.Execute("var converter = new Showdown.converter()");
engine.SetGlobalValue("text", NormalizeText(@"
Showdown Demo
-------------
You can try out Showdown on this page:
- Type some [Markdown] text on the left side.
- See the corresponding HTML on the right.
For a Markdown cheat-sheet, switch the right-hand window from *Preview* to *Syntax Guide*."));
Assert.AreEqual(NormalizeText(@"
<h2>Showdown Demo</h2>
<p>You can try out Showdown on this page:</p>
<ul>
<li>Type some [Markdown] text on the left side.</li>
<li>See the corresponding HTML on the right.</li>
</ul>
<p>For a Markdown cheat-sheet, switch the right-hand window from <em>Preview</em> to <em>Syntax Guide</em>.</p>"),
NormalizeText(engine.Evaluate<string>("converter.makeHtml(text)")));
}
Sources: Unit Tests/Real-world/RealWorldTests.cs:13-43
Built-in Object Implementation
Core ECMAScript built-in objects and functions are implemented as .NET classes. Auto-generated stub files are used to define the properties and methods of these built-ins, which then call the underlying C# implementation.
For example, the Reflect object's methods are defined in Reflect.g.cs, which maps JavaScript calls to static C# methods in the ReflectObject class.
// From: Jurassic/Library/Reflect/Reflect.g.cs
private static List<PropertyNameAndValue> GetDeclarativeProperties(ScriptEngine engine)
{
return new List<PropertyNameAndValue>(17)
{
new PropertyNameAndValue("apply", new ClrStubFunction(engine, "apply", 3, __STUB__Apply), PropertyAttributes.NonEnumerable),
new PropertyNameAndValue("construct", new ClrStubFunction(engine, "construct", 2, __STUB__Construct), PropertyAttributes.NonEnumerable),
// ... other Reflect methods
};
}
private static object __STUB__Apply(ScriptEngine engine, object thisObj, object[] args)
{
// ... argument checking and conversion
return Apply(TypeConverter.ToObject<FunctionInstance>(engine, args[0]), args[1], TypeConverter.ToObject(engine, args[2]));
}
Sources: Jurassic/Library/Reflect/Reflect.g.cs:11-20, Jurassic/Library/Reflect/Reflect.g.cs:22-33
Similarly, global functions like decodeURI and eval are implemented in GlobalObject.cs, and RegExp instance methods are defined in RegExpInstance.g.cs.
Sources: Jurassic/Library/GlobalObject.cs:42-102, Jurassic/Library/RegExp/RegExpInstance.g.cs:11-60
Summary
Jurassic prioritizes strong ECMAScript compatibility. It achieves full compliance with ES3 and ES5 and is actively developing support for ES6. This compliance is rigorously verified through a comprehensive testing strategy that includes standardized test suites (Kangax, test262) and validation against a wide array of popular, real-world JavaScript libraries. This ensures that Jurassic is not only compliant with the specification on paper but is also a practical and reliable engine for executing complex JavaScript code in a .NET environment.
Sources: README.md, Unit Tests/Real-world/RealWorldTests.cs, Test Suite Runner/Kangax/compat-table.json