Compile-time `with` for strict mode JavaScript
The `with` package provides a utility to transform JavaScript code, effectively simulating the behavior of the deprecated `with` statement at compile time. This allows developers to safely use `with`-like scoping in strict mode environments and ensures compatibility with minification tools, which typically struggle with native `with`. Currently at version 7.0.2, the package maintains an active release cadence with minor bug fixes and performance improvements following major version updates. Key differentiators include its strict mode compatibility, predictable variable assignment within the generated scope (unlike native `with` which can leak assignments), and the explicit declaration of all non-excluded variables, enabling `if (foo === undefined)` checks. It also offers detailed parsing errors for easier debugging.
Common errors
-
SyntaxError: 'with' statement is not allowed in strict mode
cause Attempting to use the native JavaScript `with` statement in a strict mode context, which is disallowed.fixUse the `with` package's `addWith` utility to generate strict-mode-safe code, as native `with` is deprecated and problematic. For example: `addWith('data', 'console.log(myVar)');` instead of `with (data) { console.log(myVar); }` -
Error: Syntax Error: Unexpected token (X:Y) at (...)
cause The `src` or `obj` string passed to `addWith` contains invalid JavaScript syntax that the internal Babel parser cannot process.fixReview the `src` and `obj` strings for syntax errors. The error object returned by `addWith` will contain `error.babylonError` with detailed location information (line, column) and `error.component` ('src' or 'obj') to pinpoint the issue.
Warnings
- breaking Version 7.0.0 dropped support for Node.js versions older than 10.0.0. Projects using older Node.js runtimes must upgrade Node.js or stick to `with` v6.x.x.
- gotcha Assignments to variables within the `addWith` generated code (e.g., `foo = 'bar'`) will always remain contained within the generated 'with' block's scope. They will NOT modify properties on the original `obj` or variables in the outer scope, which is a key difference from native JavaScript `with` behavior.
- gotcha Variables not explicitly listed in the `exclude` array are always declared within the generated scope, meaning `if (foo === undefined)` can be used instead of `if (typeof foo === 'undefined')`. If a variable is excluded, it's ignored entirely, which can improve efficiency but means it won't be declared.
- gotcha The package uses Babel (specifically, Babylon, its parser) internally to parse the input `src` and `obj` code. Syntax errors in the input will result in an error object wrapping the original Babylon error, accessible via `error.babylonError` and `error.component` (indicating 'src' or 'obj').
Install
-
npm install with -
yarn add with -
pnpm add with
Imports
- addWith
const addWith = require('with');import addWith from 'with';
- addWith
var addWith = require('with'); - addWith (Type)
import addWith from 'with'; // `addWith` is a function with the signature: // (obj: string, src: string, exclude?: string[]) => string;
Quickstart
import addWith from 'with';
// Basic usage: injects 'obj' properties into scope
const code1 = addWith('obj', 'console.log(a)');
console.log('// Code 1:\n', code1);
// Expected output (simplified for brevity): ';(function (console, a) { console.log(a) }(...));'
// Usage with exclusion: 'console' is treated as global/external
const code2 = addWith('obj', 'console.log(a)', ['console']);
console.log('\n// Code 2:\n', code2);
// Expected output (simplified for brevity): ';(function (a) { console.log(a) }(...));'
// Example of how the generated code behaves differently from native `with`
const generatedCodeExample = `
const outerFoo = 'original';
const obj = { foo: 'objFoo' };
const addWithResult = addWith('obj', 'foo = \'modified\';', []);
// To run this, you'd typically need a code execution context like a VM or eval
// For demonstration, let's just log the expected behavior difference.
// If this were native 'with (obj) { foo = 'modified'; }',
// obj.foo would become 'modified'.
// With compile-time 'with', `foo` becomes a local variable within the generated scope,
// and assignments to `foo` do not affect `obj.foo` or `outerFoo`.
`;
console.log('\n// Example illustrating behavior difference with assignments (conceptual):');
console.log(generatedCodeExample);