# SandboxJS - ECMAScript Feature Status [![codecov](https://codecov.io/gh/nyariv/SandboxJS/branch/main/graph/badge.svg)](https://codecov.io/gh/nyariv/SandboxJS) This document describes the current implementation status of ECMAScript features in SandboxJS. **Test Coverage**: 1598 total tests | Code Coverage: ~97% statement coverage, ~92% branch coverage --- ## 🐛 Known Bugs & Limitations The following limitations have been identified during testing: 1. **Unicode identifier escapes** - `\uXXXX` escape sequences in variable names are not supported --- ## ✅ Supported Features SandboxJS supports the following ECMAScript features with comprehensive test coverage: ### Arithmetic Operators - ✅ **Addition** - `1+1` → `2` - ✅ **Subtraction** - `1 * 2 + 3 * (4 + 5) * 6` → `164` - ✅ **Multiplication** - `1 * 2` → `2` - ✅ **Division** - `1+2*4/5-6+7/8 % 9+10-11-12/13*14` → `-16.448...` - ✅ **Modulus** - `test2 %= 1` → `0` - ✅ **Exponentiation** - `2 ** 3` → `8`, `3 ** 2 ** 2` → `81` - ✅ **Exponentiation assignment** - `test2 **= 0` → `1` - ✅ **Unary plus** - `+'1'` → `1` - ✅ **Unary minus** - `-'1'` → `-1` ### Logical Operators - ✅ **Logical AND** - `true && true || false` → `true` - ✅ **Logical OR** - `test2 || false` → `3` - ✅ **Logical NOT** - `!test2` → `false`, `!!test2` → `true` - ✅ **Nullish coalescing** - `null ?? 'default'` → `'default'`, `0 ?? 'default'` → `0` ### Comparison Operators - ✅ **Equality** - `test2 == '3'` → `true` - ✅ **Strict equality** - `test2 === '3'` → `false` - ✅ **Inequality** - `test2 != '3'` → `false` - ✅ **Strict inequality** - `test2 !== '3'` → `true` - ✅ **Less than** - `test2 < 3` → `false` - ✅ **Greater than** - `test2 > 3` → `false` - ✅ **Less than or equal** - `test2 <= 3` → `true` - ✅ **Greater than or equal** - `test2 >= 3` → `true` ### Bitwise Operators - ✅ **Bitwise AND** - `test2 & 1` → `1` - ✅ **Bitwise OR** - `test2 | 4` → `7` - ✅ **Bitwise NOT** - `~test2` → `-2` - ✅ **Bitwise XOR** - `test2 ^= 1` → `1` - ✅ **Left shift** - Tested in complex expressions - ✅ **Right shift** - Tested in complex expressions - ✅ **Unsigned right shift** - Tested in complex expressions - ✅ **Left shift assignment** - `let x = 5; x <<= 1` → `10` - ✅ **Right shift assignment** - `let x = 8; x >>= 1` → `4` - ✅ **Unsigned right shift assignment** - `let x = 8; x >>>= 2` → `2` - ✅ **XOR assignment** - `test2 ^= 1` → `1` - ✅ **AND assignment** - `test2 &= 3` → `1` - ✅ **OR assignment** - `test2 |= 2` → `3` ### Assignment Operators - ✅ **Simple assignment** - `test2 = 1` → `1` - ✅ **Addition assignment** - `test2 += 1` → `2` - ✅ **Subtraction assignment** - `test2 -= 1` → `1` - ✅ **Multiplication assignment** - `test2 *= 2` → `2` - ✅ **Division assignment** - `test2 /= 2` → `1` - ✅ **Exponentiation assignment** - `test2 **= 0` → `1` - ✅ **Modulus assignment** - `test2 %= 1` → `0` - ✅ **XOR assignment** - `test2 ^= 1` → `1` - ✅ **AND assignment** - `test2 &= 3` → `1` - ✅ **OR assignment** - `test2 |= 2` → `3` - ✅ **Logical AND assignment (&&=)** - `let x = 10; x &&= 5` → `5` - ✅ **Logical OR assignment (||=)** - `let x = 0; x ||= 5` → `5` - ✅ **Nullish coalescing assignment (??=)** - `let x = null; x ??= 5` → `5` - ✅ **Post-increment** - `test2++` → `1` - ✅ **Pre-increment** - `++test2` → `3` ### Other Operators - ✅ **Conditional (ternary)** - `test[test2] ? true : false ? 'not ok' : 'ok'` → `'ok'` - ✅ **Optional chaining** - `!({}).a?.a` → `true`, `({}).a?.toString()` → `undefined` - ✅ **Comma operator** - `1,2` → `2` - ✅ **typeof** - `typeof '1'` → `'string'`, `typeof x === 'undefined'` → `true` - ✅ **instanceof** - `{} instanceof Object` → `true` - ✅ **in operator** - `'a' in {a: 1}` → `true` - ✅ **delete operator** - `delete 1` → `true`, `let a = {b: 1}; return delete a.b` → `true` - ✅ **void operator** - `void 2 == '2'` → `false` - ✅ **new operator** - `new Date(0).toISOString()` → `'1970-01-01T00:00:00.000Z'` ### Data Types - ✅ **Numbers** - `2.2204460492503130808472633361816E-16` → Scientific notation - ✅ **BigInt** - `(1n + 0x1n).toString()` → `'2'` - ✅ **Binary literals** - `0b1010` → `10`, `0B1111` → `15`, `0b1010n` → `'10'` (BigInt), `0b1_000` → `8` (with separators) - ✅ **Octal literals** - `0o17` → `15`, `0O77` → `63`, `0o17n` → `'15'` (BigInt), `0o7_777` → `4095` (with separators) - ✅ **Strings** - `"test2"` → `'test2'` - ✅ **Template literals** - `` `test2 is ${`also ${test2}`}` `` → `'test2 is also 1'` - ✅ **Tagged template functions** - ``tag`hello ${"world"}` `` → function receives string parts and interpolated values - ✅ **Escape sequences** - `"\\"` → `'\\'`, `"\\xd9"` → `'Ù'`, `"\\n"` → `'\n'` - ✅ **Boolean** - `true`, `false` - ✅ **null** - `null ?? 'default'` → `'default'` - ✅ **undefined** - `typeof x === 'undefined'` → `true` - ✅ **Arrays** - `[test2, 2]` → `[1, 2]` - ✅ **Objects** - `{"aa": test[0](), b: test2 * 3}` → `{ "aa": 1, "b": 3 }` - ✅ **Regular expressions** - `/a/.test('a')` → `true`, `/a/i.test('A')` → `true` ### Objects & Arrays - ✅ **Object literals** - `{a: 1, b: 2}` → `{ a: 1, b: 2 }` - ✅ **Array literals** - `[1, 2]` → `[1, 2]` - ✅ **Property access (dot)** - `a.b.c` → `2` - ✅ **Property access (bracket)** - `a['b']['c']` → `2` - ✅ **Computed property names** - `{"aa": test[0]()}` → `{ "aa": 1 }` - ✅ **Object spread** - `{a: 1, ...{b: 2, c: {d: test2,}}, e: 5}` → Full object - ✅ **Array spread** - `[1, ...[2, [test2, 4]], 5]` → `[1, 2, [3, 4], 5]` - ✅ **Object method shorthand** - `let y = {a: 1, b(x) {return this.a + x}}; return y.b(2)` → `3` ### Functions - ✅ **Function declarations** - `function f(a) { return a + 1 } return f(2);` → `3` - ✅ **Function expressions** - `(function () { return 1 })()` → `1` - ✅ **Arrow functions (single param)** - `(a => a + 1)(1)` → `2` - ✅ **Arrow functions (multiple params)** - `((a) => {return a + 1})(1)` → `2` - ✅ **Arrow functions (expression body)** - `(a => a + 1)(1)` → `2` - ✅ **Arrow functions (block body)** - `(() => {return 1})()` → `1` - ✅ **Async arrow functions** - `(async () => 1)()` → `1` - ✅ **Async function expressions** - `(async () => await 1)()` → `1` - ✅ **Rest parameters** - `[0,1].filter((...args) => args[1])` → `[1]` - ✅ **Parameter default values** - `function fn(a = 1) { return a; }` → `1` - ✅ **Spread in function calls** - `Math.pow(...[2, 2])` → `4` - ✅ **Constructor functions** - `function LinkedListNode(e){this.value=e,this.next=null}` with `new` - ✅ **Recursive functions** - Linked list reverse example #### Destructuring - ✅ **Array destructuring** - `const [a, b] = [1, 2]` - ✅ **Object destructuring** - `const {a, b} = {a: 1, b: 2}` - ✅ **Nested destructuring** - `const {a: {b}} = {a: {b: 42}}` - ✅ **Destructuring with defaults** - `const {a = 1} = {}` - ✅ **Custom variable names (renaming)** - `const {a: myA} = {a: 1}` - ✅ **Destructuring in function parameters** - `function fn({a, b}) { }` - ✅ **Rest in destructuring** - `const [a, ...rest] = [1, 2, 3]`, `const {a, ...rest} = obj` - ✅ **Computed property names in destructuring** - `const {[key]: val} = obj` - ✅ **Destructuring in for-of/for-in loops** - `for (const [a, b] of arr) { }` - ✅ **Destructuring in function parameters with defaults** - `function fn({a = 1, b = 2} = {}) { }` ### Control Flow #### Conditionals - ✅ **if statement** - `if (true) { return true; } else return false` → `true` - ✅ **else statement** - `if (false) { return true; } else return false` → `false` - ✅ **if/else chains** - `if (false) return true; else if (false) {return true} else return false` → `false` - ✅ **Nested if statements** - Complex nested if/else with 9 levels - ✅ **Inline ternary** - `true ? 1 : 2` → `1` #### Loops - ✅ **for loop** - `let x; for(let i = 0; i < 2; i++){ x = i }; return x;` → `1` - ✅ **while loop** - `let x = 2; while(--x){ }; return x;` → `0` - ✅ **do-while loop** - `let x = 1; do {x++} while(x < 1); return x;` → `2` - ✅ **for-of loop** - `for(let i of [1,2]){ return i };` → `1` - ✅ **for-in loop** - `for(let i in [1,2]){ return i };` → `'0'` - ✅ **break statement** - `for(let i = 0; i < 2; i++){ x = i; break; }` → Exits early - ✅ **continue statement** - `for (let i = 0; i < 5; i++) { if (i === 2) continue; sum += i; }` → Skips iteration #### Switch - ✅ **switch statement** - `switch(1) {case 1: b = 2; break; case 2: b = 3; default: b = 4}; return b` → `2` - ✅ **case clauses** - Multiple case tests - ✅ **default clause** - `switch(3) {case 1: b = 2; break; case 2: b = 3; default: b = 4}; return b` → `4` - ✅ **Fall-through behavior** - `switch(1) {case 1:b = 2; case 2: b = 3; default: b = 4}; return b` → `4` #### Error Handling - ✅ **try/catch** - `try {a.x.a} catch {return 1}; return 2` → `1` - ✅ **try/catch with exception variable** - `try { throw new Error('msg'); } catch(e) { return e.message; }` → `'msg'` - ✅ **finally block** - `try { return 1; } finally { x = 2; }` → Finally executes before return - ✅ **finally overrides return** - `try { return 1; } finally { return 2; }` → `2` - ✅ **finally overrides error** - `try { throw Error('a'); } finally { throw Error('b'); }` → Error: 'b' - ✅ **throw statement** - `throw new Error('test')` → Error with message #### Other - ✅ **Code blocks** - `{let j = 1; i += j;}` → Block scope - ✅ **this binding** - `let y = {a: 1, b(x) {return this.a + x}}` → Method context - ✅ **Closures** - `const a = () => {return 1}; const b = () => {return 2}; return (() => a() + b())()` → `3` ### Variables - ✅ **var declaration** - `var i = 1; return i + 1` → `2` - ✅ **let declaration** - `let j = 1; return j + 1` → `2` - ✅ **const declaration** - `const k = 1; return k + 1` → `2` - ✅ **const immutability** - `const l = 1; return l = 2` → Error ### Async/Await - ✅ **async functions** - `(async () => 1)()` → Promise resolves to `1` - ✅ **await keyword** - `(async () => await 1)()` → `1` - ✅ **await with promises** - `(async () => await (async () => 1)())()` → `1` - ✅ **async with variables** - `let p = (async () => 1)(); return (async () => 'i = ' + await p)()` → `'i = 1'` - ✅ **Async arrow functions** - `let i = 0; (async () => i += 1)(); return i;` → `1` - ✅ **for-await-of loops** - `for await (const item of asyncIterable) { }` #### Generators (ES6) - ✅ **Generator functions (function*)** - `function* gen() { yield 1; }` - ✅ **yield keyword** - ✅ **`yield` as expression value** - `const x = yield 1` - ✅ **yield* delegation** - ✅ **Async generators** - `async function* gen() { yield 1; }` - ✅ **Iterator `.return()`/`.throw()`** - Protocol methods for early termination and error injection - ✅ **`next(value)` injection** - Sending values back into a paused generator ### Other Built-in Objects - ✅ **WeakMap** - All methods work: `set()`, `get()`, `has()`, `delete()` (6 tests) - ✅ **WeakSet** - All methods work: `add()`, `has()`, `delete()` ### Comments - ✅ **Single-line comments** - `1 // 2` → `1` - ✅ **Multi-line comments** - `/* 2 */ 1` → `1` ### Operator Precedence Comprehensive operator precedence testing has been implemented with 35 tests covering: - NOT (!) with comparison operators - Logical NOT with AND/OR - Comparison operator chaining - Bitwise vs logical operators - Bitwise shift with arithmetic - Mixed bitwise operators (correct precedence: shift > & > ^ > |) - Exponentiation (right-associative) - typeof, delete, void with various operators - Optional chaining and nullish coalescing - Increment/decrement with arithmetic - Multiple unary operators - Comma operator in expressions --- ## ❌ Not Supported Features The following ECMAScript features are not currently supported in SandboxJS: ### HIGH PRIORITY #### Classes (ES6) - ❌ **class declarations** - ❌ **extends keyword (inheritance)** - ❌ **super keyword** - ❌ **Static methods** - ❌ **Class fields (public)** - ❌ **Private fields (#field)** - ❌ **Private methods** - ❌ **Static class fields** - ❌ **Static initialization blocks** #### Object Features - ❌ **Getters in object literals** - `{get prop() { return 1; }}` - ❌ **Setters in object literals** - `{set prop(v) { this.val = v; }}` ### LOW PRIORITY #### Modules Module features are not supported by design as SandboxJS is intended for sandboxed code execution: - ❌ **import statements** - ❌ **export statements** - ❌ **Dynamic import()** - ❌ **import.meta** --- ## 🔒 Security-Related Restrictions (Intentionally Blocked) These features are intentionally blocked for security reasons: - 🔒 Direct access to global scope - 🔒 Access to `__proto__` (prototype pollution prevention) - 🔒 Global object pollution - 🔒 Prototype method overriding - 🔒 Access to non-whitelisted globals - 🔒 Access to non-whitelisted prototype methods - 🔒 `with` statement - 🔒 `arguments` object (security risk, use rest parameters `...args` instead) - 🔒 Execution beyond quota limits --- ## 📝 Notes - **Priority Levels**: - **HIGH**: Common patterns used frequently in production code - **MEDIUM**: Less common but still important for completeness - **LOW**: Edge cases and advanced features with limited use - **Implementation Focus**: SandboxJS focuses on core ES5-ES2018 features with strong security controls - **Performance**: Advanced meta-programming features are omitted to maintain sandbox safety