UNPKG

jsesc-es

Version:

Given some data, jsesc returns the shortest possible stringified & ASCII-safe representation of that data.

591 lines (432 loc) 17 kB
# jsesc-es <div align="center"> [![npm version](https://img.shields.io/npm/v/jsesc-es.svg)](https://www.npmjs.com/package/jsesc-es) [![npm downloads](https://img.shields.io/npm/dm/jsesc-es.svg)](https://www.npmjs.com/package/jsesc-es) [![jsdelivr](https://data.jsdelivr.com/v1/package/npm/jsesc-es/badge)](https://www.jsdelivr.com/package/npm/jsesc-es) [![unpkg](https://img.shields.io/badge/unpkg-jsesc--es-blue.svg)](https://unpkg.com/jsesc-es/) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/) [![ES Modules](https://img.shields.io/badge/ES-Modules-brightgreen.svg)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) **English** | **[简体中文](README.zh-CN.md)** </div> > A modern TypeScript + ESM refactor of the popular [jsesc](https://github.com/mathiasbynens/jsesc) library with 100% API compatibility Given some data, _jsesc-es_ returns a stringified representation of that data. jsesc-es is similar to `JSON.stringify()` except: 1. it outputs JavaScript instead of JSON [by default](#json), enabling support for data structures like ES6 maps and sets; 2. it offers [many options](#api) to customize the output; 3. its output is ASCII-safe [by default](#minimal), thanks to its use of [escape sequences](https://mathiasbynens.be/notes/javascript-escapes) where needed; 4. **NEW**: Full TypeScript support with comprehensive type definitions; 5. **NEW**: Native ES Modules with tree-shaking support; 6. **NEW**: Modern development toolchain and improved performance. For any input, jsesc-es generates the shortest possible valid printable-ASCII-only output. [Here's an online demo.](https://mothereff.in/js-escapes) jsesc-es's output can be used instead of `JSON.stringify`'s to avoid [mojibake](https://en.wikipedia.org/wiki/Mojibake) and other encoding issues, or even to [avoid errors](https://twitter.com/annevk/status/380000829643571200) when passing JSON-formatted data (which may contain U+2028 LINE SEPARATOR, U+2029 PARAGRAPH SEPARATOR, or [lone surrogates](https://esdiscuss.org/topic/code-points-vs-unicode-scalar-values#content-14)) to a JavaScript parser or an UTF-8 encoder. ## ✨ What's New in jsesc-es ### 🔥 TypeScript First - **Built-in type definitions** - No need for `@types/jsesc` - **Full type safety** with comprehensive `JsescOptions` interface - **Better IDE support** with IntelliSense and auto-completion - **Type-safe option validation** at compile time ### 📦 Modern Module System - **Native ES Modules** with tree-shaking support - **Multiple import styles** - default, named, or mixed imports - **CommonJS compatibility** for legacy projects - **Optimized bundle size** with modern build tools ### ⚡ Enhanced Performance - **Improved function handling** with better type detection - **Optimized escape logic** for common use cases - **Modern JavaScript features** for better performance - **Reduced bundle overhead** compared to the original ### 🛠️ Developer Experience - **Modern toolchain** with Vitest, tsdown, and pnpm - **Better error messages** with TypeScript integration - **Comprehensive test coverage** with type checking - **Active maintenance** with regular updates ## Installation ```bash # pnpm (recommended) - https://pnpm.io/ pnpm add jsesc-es # yarn - https://yarnpkg.com/ yarn add jsesc-es # npm - https://www.npmjs.com/ npm install jsesc-es # Or other runtime linke... # bun - https://bun.sh/ bun add jsesc-es # deno - https://deno.land/ deno add jsesc-es ``` ## Usage ### ES Modules (Recommended) ```typescript // Default import (most common) import jsesc from 'jsesc-es' // Named import import { jsesc } from 'jsesc-es' // Import with types (TypeScript) import type { JsescOptions } from 'jsesc-es' import jsesc from 'jsesc-es' // Import version info import { version } from 'jsesc-es' // Mixed import (not recommended) import jsesc, { version, type JsescOptions } from 'jsesc-es' ``` ### TypeScript Usage ```typescript import type { JsescOptions } from 'jsesc-es' import jsesc from 'jsesc-es' // Type-safe options const options: JsescOptions = { quotes: 'single', wrap: true, es6: true, minimal: false } // Type-safe function usage function escapeForHTML(input: string): string { return jsesc(input, { quotes: 'double', wrap: true, isScriptContext: true }) } // Type-safe configuration objects const configs = { json: { json: true } as JsescOptions, minimal: { minimal: true } as JsescOptions, es6: { es6: true, quotes: 'backtick' } as JsescOptions } ``` ### CommonJS (Legacy Support) ```javascript // CommonJS require (still supported) const jsesc = require('jsesc-es') // Dynamic import (modern alternative) const { jsesc } = await import('jsesc-es') ``` ### Node.js ESM Ensure your `package.json` includes: ```json { "type": "module" } ``` Or use `.mjs` file extension: ```javascript // app.mjs import jsesc from 'jsesc-es' ``` ## API ### `jsesc(value, options?)` This function takes a value and returns an escaped version of the value where any characters that are not printable ASCII symbols are escaped using the shortest possible (but valid) [escape sequences for use in JavaScript strings](https://mathiasbynens.be/notes/javascript-escapes). The first supported value type is strings: ```js jsesc('Ich ♥ Bücher') // → 'Ich \\u2665 B\\xFCcher' jsesc('foo 𝌆 bar') // → 'foo \\uD834\\uDF06 bar' ``` Instead of a string, the `value` can also be an array, an object, a map, a set, a number, a BigInt, or a buffer. In such cases, `jsesc` returns a stringified version of the value where any characters that are not printable ASCII symbols are escaped in the same way. ```js // Escaping an array jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ]) // → '[\'Ich \\u2665 B\\xFCcher\',\'foo \\uD834\\uDF06 bar\']' // Escaping an object jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }) // → '{\'Ich \\u2665 B\\xFCcher\':\'foo \\uD834\\uDF06 bar\'}' ``` ### Options The optional `options` argument accepts an object with the following options. In TypeScript, use the `JsescOptions` type for full type safety: ```typescript import { type JsescOptions } from 'jsesc-es' const options: JsescOptions = { // Your options here with full IntelliSense support } ``` #### `quotes` The default value for the `quotes` option is `'single'`. This means that any occurrences of `'` in the input string are escaped as `\'`, so that the output can be used in a string literal wrapped in single quotes. ```js jsesc('`Lorem` ipsum "dolor" sit \'amet\' etc.') // → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.' jsesc('`Lorem` ipsum "dolor" sit \'amet\' etc.', { quotes: 'single' }) // → '`Lorem` ipsum "dolor" sit \\\'amet\\\' etc.' ``` If you want to use the output as part of a string literal wrapped in double quotes, set the `quotes` option to `'double'`. ```js jsesc('`Lorem` ipsum "dolor" sit \'amet\' etc.', { quotes: 'double' }) // → '`Lorem` ipsum \\"dolor\\" sit \'amet\' etc.' ``` If you want to use the output as part of a template literal (i.e. wrapped in backticks), set the `quotes` option to `'backtick'`. ```js jsesc('`Lorem` ipsum "dolor" sit \'amet\' etc.', { quotes: 'backtick' }) // → '\\`Lorem\\` ipsum "dolor" sit \'amet\' etc.' ``` #### `numbers` The default value for the `numbers` option is `'decimal'`. This means that any numeric values are represented using decimal integer literals. Other valid options are `binary`, `octal`, and `hexadecimal`. ```js jsesc(42, { numbers: 'binary' }) // → '0b101010' jsesc(42, { numbers: 'octal' }) // → '0o52' jsesc(42, { numbers: 'decimal' }) // → '42' jsesc(42, { numbers: 'hexadecimal' }) // → '0x2A' ``` #### `wrap` The `wrap` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output is a valid JavaScript string literal wrapped in quotes. ```js jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', { quotes: 'single', wrap: true }) // → '\'Lorem ipsum "dolor" sit \\\'amet\\\' etc.\'' jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', { quotes: 'double', wrap: true }) // → '"Lorem ipsum \\"dolor\\" sit \'amet\' etc."' ``` #### `es6` The `es6` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, any astral Unicode symbols in the input are escaped using [ECMAScript 6 Unicode code point escape sequences](https://mathiasbynens.be/notes/javascript-escapes#unicode-code-point). ```js // By default, the `es6` option is disabled: jsesc('foo 𝌆 bar 💩 baz') // → 'foo \\uD834\\uDF06 bar \\uD83D\\uDCA9 baz' // To enable it: jsesc('foo 𝌆 bar 💩 baz', { es6: true }) // → 'foo \\u{1D306} bar \\u{1F4A9} baz' ``` #### `escapeEverything` The `escapeEverything` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, all the symbols in the output are escaped — even printable ASCII symbols. ```js jsesc('lolwat"foo\'bar', { escapeEverything: true }) // → '\\x6C\\x6F\\x6C\\x77\\x61\\x74\\"\\x66\\x6F\\x6F\\\'\\x62\\x61\\x72' ``` #### `minimal` The `minimal` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, only a limited set of symbols in the output are escaped. **Note:** with this option enabled, jsesc-es output is no longer guaranteed to be ASCII-safe. ```js jsesc('foo\u2029bar\nbaz©qux𝌆flops', { minimal: true }) // → 'foo\\u2029bar\\nbaz©qux𝌆flops' ``` #### `isScriptContext` The `isScriptContext` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, occurrences of [`</script` and `</style`](https://mathiasbynens.be/notes/etago) in the output are escaped. ```js jsesc('foo</script>bar', { isScriptContext: true }) // → 'foo<\\/script>bar' ``` #### `compact` The `compact` option takes a boolean value (`true` or `false`), and defaults to `true` (enabled). When enabled, the output for arrays and objects is as compact as possible. ```js jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { compact: true // this is the default }) // → '{\'Ich \u2665 B\xFCcher\':\'foo \uD834\uDF06 bar\'}' jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { compact: false }) // → '{\n\t\'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}' ``` #### `indent` The `indent` option takes a string value, and defaults to `'\t'`. When the `compact` setting is disabled (`false`), the value of the `indent` option is used to format the output. ```js jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, { compact: false, indent: ' ' }) // → '{\n \'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}' ``` #### `indentLevel` The `indentLevel` option takes a numeric value, and defaults to `0`. It represents the current indentation level. ```js jsesc(['a', 'b', 'c'], { compact: false, indentLevel: 1 }) // → '[\n\t\t\'a\',\n\t\t\'b\',\n\t\t\'c\'\n\t]' ``` #### `json` The `json` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output is valid JSON. ```js jsesc('foo\x00bar\xFF\uFFFDbaz', { json: true }) // → '"foo\\u0000bar\\u00FF\\uFFFDbaz"' jsesc({ 'foo\x00bar\xFF\uFFFDbaz': 'foo\x00bar\xFF\uFFFDbaz' }, { json: true }) // → '{"foo\\u0000bar\\u00FF\\uFFFDbaz":"foo\\u0000bar\\u00FF\\uFFFDbaz"}' ``` #### `lowercaseHex` The `lowercaseHex` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, any alphabetical hexadecimal digits in escape sequences are in lowercase. ```js jsesc('Ich ♥ Bücher', { lowercaseHex: true }) // → 'Ich \\u2665 B\\xfccher' // ^^ jsesc(42, { numbers: 'hexadecimal', lowercaseHex: true }) // → '0x2a' // ^^ ``` ### Version Information ```typescript // Access version information import jsesc, { version } from 'jsesc-es' console.log(jsesc.version) // e.g., "0.0.3" console.log(version) // e.g., "0.0.3" ``` ## Migration from jsesc Migrating from the original `jsesc` library is straightforward: ### 1. Update Dependencies ```bash # Remove old package npm uninstall jsesc # Install new package npm install jsesc-es ``` ### 2. Update Imports ```javascript // Before (CommonJS) const jsesc = require('jsesc') // After (ES Modules) import jsesc from 'jsesc-es' // Or with types (TypeScript) import jsesc, { type JsescOptions } from 'jsesc-es' ``` ### 3. Enjoy Enhanced Features - **Full TypeScript support** with no additional setup - **Better IDE experience** with IntelliSense - **Modern module system** with tree-shaking - **100% API compatibility** - no code changes needed For detailed migration instructions, see [MIGRATION.md](./MIGRATION.md). ## TypeScript Examples ### Creating Utility Functions ```typescript import jsesc, { type JsescOptions } from 'jsesc-es' // Create type-safe utility functions const createEscaper = (defaultOptions: JsescOptions) => { return (input: string, options?: Partial<JsescOptions>): string => { return jsesc(input, { ...defaultOptions, ...options }) } } // Pre-configured escapers const escapeForHTML = createEscaper({ quotes: 'double', wrap: true, isScriptContext: true }) const escapeForJSON = createEscaper({ json: true }) const escapeMinimal = createEscaper({ minimal: true }) // Usage with full type safety const htmlSafe = escapeForHTML('Hello "World"') const jsonSafe = escapeForJSON({ message: 'Hello 世界' }) const minimalEscape = escapeMinimal('Simple text') ``` ### Advanced Configuration ```typescript import { type JsescOptions } from 'jsesc-es' // Define configuration presets const PRESETS: Record<string, JsescOptions> = { html: { quotes: 'double', wrap: true, isScriptContext: true, escapeEverything: false }, json: { json: true, compact: true }, es6: { es6: true, quotes: 'backtick', wrap: true }, debug: { escapeEverything: true, compact: false, indent: ' ' } } as const // Type-safe preset usage function escapeWithPreset( input: any, preset: keyof typeof PRESETS, overrides?: Partial<JsescOptions> ): string { const config = { ...PRESETS[preset], ...overrides } return jsesc(input, config) } ``` ## Performance jsesc-es includes several performance improvements over the original: - **Optimized type checking** for better runtime performance - **Improved function handling** with enhanced detection logic - **Modern JavaScript features** for better engine optimization - **Reduced overhead** in common escape scenarios - **Tree-shaking support** for smaller bundle sizes ## Browser Support jsesc-es provides broad compatibility through its dual build system: ### Runtime Requirements **For ES Modules (recommended):** - **Node.js**: 14+ (native ESM support) - **Browsers**: Chrome 61+, Firefox 60+, Safari 10.1+, Edge 16+ - **ES Modules**: Native support required **For CommonJS (legacy):** - **Node.js**: 6+ (transpiled output) - **Browsers**: Chrome 27+, Firefox 3+, Safari 4+, Opera 10+ (with bundler) ### Build Targets vs. Module System While jsesc-es maintains compatibility with legacy environments through its transpiled CommonJS build (targeting node6, chrome27, etc.), **ES Modules require modern environments** that support the `import`/`export` syntax natively. The build targets ensure the *JavaScript syntax and APIs* work in older environments, but the *module system itself* has minimum version requirements. **Key Points:** - 📦 **CommonJS build**: Works in very old environments (Node 6+, Chrome 27+) - 🚀 **ESM build**: Requires modern environments with native ESM support - 🔧 **Legacy projects**: Use CommonJS or transpile ESM with Babel/TypeScript -**Modern projects**: Use ESM for better tree-shaking and performance ### TypeScript Support - **TypeScript**: 4.5+ - **Built-in types**: No `@types/` package needed ## Development ```bash # Clone the repository git clone https://github.com/Drswith/jsesc-es.git cd jsesc-es # Install dependencies pnpm install # Run tests pnpm test # Build the project pnpm build # Type checking pnpm typecheck # Linting pnpm lint ``` ## Contributing Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests. ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Acknowledgments - **[Mathias Bynens](https://github.com/mathiasbynens)** - Creator of the original [jsesc](https://github.com/mathiasbynens/jsesc) library - **The TypeScript team** - For excellent tooling and type system - **The open source community** - For continuous feedback and contributions --- **jsesc-es** - A modern, TypeScript-first approach to JavaScript string escaping. 🚀