Skip to content

Latest commit

 

History

History
599 lines (433 loc) · 15.8 KB

File metadata and controls

599 lines (433 loc) · 15.8 KB

jsesc-es

npm version npm downloads jsdelivr unpkg TypeScript ES Modules License: MIT

English | 简体中文

基于流行的 jsesc 库,使用现代 TypeScript + ESM 重构,100% API 兼容

给定一些数据,jsesc-es 返回该数据的字符串化表示。jsesc-es 类似于 JSON.stringify(),但有以下不同:

  1. 默认情况下输出 JavaScript 而不是 JSON,支持 ES6 map 和 set 等数据结构;
  2. 提供多种选项来自定义输出;
  3. 默认情况下输出 ASCII 安全,在需要时使用转义序列
  4. 新特性:完整的 TypeScript 支持和全面的类型定义;
  5. 新特性:原生 ES 模块,支持 tree-shaking;
  6. 新特性:现代开发工具链和改进的性能。

对于任何输入,jsesc-es 都会生成最短的有效可打印 ASCII 输出。这里有一个在线演示。

jsesc-es 的输出可以用来替代 JSON.stringify 的输出,以避免乱码和其他编码问题,甚至可以避免错误,当向 JavaScript 解析器或 UTF-8 编码器传递 JSON 格式数据(可能包含 U+2028 行分隔符、U+2029 段落分隔符或孤立代理)时。

✨ jsesc-es 的新特性

🔥 TypeScript 优先

  • 内置类型定义 - 无需 @types/jsesc
  • 完整类型安全 和全面的 JsescOptions 接口
  • 更好的 IDE 支持 包括 IntelliSense 和自动补全
  • 编译时类型安全选项验证

📦 现代模块系统

  • 原生 ES 模块 支持 tree-shaking
  • 多种导入样式 - 默认导入、命名导入或混合导入
  • CommonJS 兼容性 用于传统项目
  • 优化的包大小 配合现代构建工具

⚡ 增强性能

  • 改进的函数处理 更好的类型检测
  • 优化的转义逻辑 适用于常见用例
  • 现代 JavaScript 特性 提供更好的性能
  • 相比原版减少的包开销

🛠️ 开发体验

  • 现代工具链 使用 Vitest、tsdown 和 pnpm
  • 更好的错误消息 集成 TypeScript
  • 全面的测试覆盖 包含类型检查
  • 积极维护 定期更新

安装

# pnpm(推荐)- https://pnpm.io/
pnpm add jsesc-es

# yarn - https://yarnpkg.com/
yarn add jsesc-es

# npm - https://www.npmjs.com/
npm install jsesc-es

# 或其他运行时如...

# bun - https://bun.sh/
bun add jsesc-es

# deno - https://deno.land/
deno add jsesc-es

使用方法

ES 模块(推荐)

// 默认导入(最常见)
import jsesc from 'jsesc-es'

// 命名导入
import { jsesc } from 'jsesc-es'

// 带类型导入
import type { JsescOptions } from 'jsesc-es'
import jsesc from 'jsesc-es'

// 导入版本信息
import { version } from 'jsesc-es'

// 混合导入(不推荐)
import jsesc, { version } from 'jsesc-es'

TypeScript 使用

import type { JsescOptions } from 'jsesc-es'
import jsesc from 'jsesc-es'

// 类型安全的选项
const options: JsescOptions = {
  quotes: 'single',
  wrap: true,
  es6: true,
  minimal: false
}

// 类型安全的函数使用
function escapeForHTML(input: string): string {
  return jsesc(input, {
    quotes: 'double',
    wrap: true,
    isScriptContext: true
  })
}

// 类型安全的配置对象
const configs = {
  json: { json: true } as JsescOptions,
  minimal: { minimal: true } as JsescOptions,
  es6: { es6: true, quotes: 'backtick' } as JsescOptions
}

CommonJS(传统支持)

// CommonJS require(仍然支持)
const jsesc = require('jsesc-es')

// 动态导入(现代替代方案)
const { jsesc } = await import('jsesc-es')

Node.js ESM

确保您的 package.json 包含:

{
  "type": "module"
}

或使用 .mjs 文件扩展名:

// app.mjs
import jsesc from 'jsesc-es'

API

jsesc(value, options?)

此函数接受一个值并返回该值的转义版本,其中任何非可打印 ASCII 符号的字符都使用最短可能(但有效的)JavaScript 字符串转义序列进行转义。第一个支持的值类型是字符串:

jsesc('Ich ♥ Bücher')
// → 'Ich \\u2665 B\\xFCcher'

jsesc('foo 𝌆 bar')
// → 'foo \\uD834\\uDF06 bar'

除了字符串,value 也可以是数组、对象、map、set、数字、BigInt 或 buffer。在这种情况下,jsesc 返回值的字符串化版本,其中任何非可打印 ASCII 符号的字符都以相同方式转义。

// 转义数组
jsesc([
  'Ich ♥ Bücher',
  'foo 𝌆 bar'
])
// → '[\'Ich \\u2665 B\\xFCcher\',\'foo \\uD834\\uDF06 bar\']'

// 转义对象
jsesc({
  'Ich ♥ Bücher': 'foo 𝌆 bar'
})
// → '{\'Ich \\u2665 B\\xFCcher\':\'foo \\uD834\\uDF06 bar\'}'

配置选项

可选的 options 参数接受一个具有以下选项的对象。在 TypeScript 中,使用 JsescOptions 类型获得完整的类型安全:

import type { JsescOptions } from 'jsesc-es'

const options: JsescOptions = {
  // 您的选项在这里,享有完整的 IntelliSense 支持
}

quotes

quotes 选项的默认值是 'single'。这意味着输入字符串中出现的任何 ' 都被转义为 \',以便输出可以在用单引号包裹的字符串字面量中使用。

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.'

如果您想将输出用作用双引号包裹的字符串字面量的一部分,请将 quotes 选项设置为 'double'

jsesc('`Lorem` ipsum "dolor" sit \'amet\' etc.', {
  quotes: 'double'
})
// → '`Lorem` ipsum \\"dolor\\" sit \'amet\' etc.'

如果您想将输出用作模板字面量(即用反引号包裹)的一部分,请将 quotes 选项设置为 'backtick'

jsesc('`Lorem` ipsum "dolor" sit \'amet\' etc.', {
  quotes: 'backtick'
})
// → '\\`Lorem\\` ipsum "dolor" sit \'amet\' etc.'

numbers

numbers 选项的默认值是 'decimal'。这意味着任何数值都使用十进制整数字面量表示。其他有效选项是 binaryoctalhexadecimal

jsesc(42, { numbers: 'binary' })
// → '0b101010'

jsesc(42, { numbers: 'octal' })
// → '0o52'

jsesc(42, { numbers: 'decimal' })
// → '42'

jsesc(42, { numbers: 'hexadecimal' })
// → '0x2A'

wrap

wrap 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,输出是一个有效的 JavaScript 字符串字面量,用引号包裹。

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

es6 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,输入中的任何星界 Unicode 符号都使用 ECMAScript 6 Unicode 代码点转义序列进行转义。

// 默认情况下,`es6` 选项是禁用的:
jsesc('foo 𝌆 bar 💩 baz')
// → 'foo \\uD834\\uDF06 bar \\uD83D\\uDCA9 baz'

// 启用它:
jsesc('foo 𝌆 bar 💩 baz', {
  es6: true
})
// → 'foo \\u{1D306} bar \\u{1F4A9} baz'

escapeEverything

escapeEverything 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,输出中的所有符号都被转义——甚至是可打印的 ASCII 符号。

jsesc('lolwat"foo\'bar', {
  escapeEverything: true
})
// → '\\x6C\\x6F\\x6C\\x77\\x61\\x74\\"\\x66\\x6F\\x6F\\\'\\x62\\x61\\x72'

minimal

minimal 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,输出中只有有限的符号集合被转义。

注意: 启用此选项后,jsesc-es 的输出不再保证是 ASCII 安全的。

jsesc('foo\u2029bar\nbaz©qux𝌆flops', {
  minimal: true
})
// → 'foo\\u2029bar\\nbaz©qux𝌆flops'

isScriptContext

isScriptContext 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,输出中出现的 </script</style 被转义。

jsesc('foo</script>bar', {
  isScriptContext: true
})
// → 'foo<\\/script>bar'

compact

compact 选项接受布尔值(truefalse),默认为 true(启用)。启用时,数组和对象的输出尽可能紧凑。

jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
  compact: true // 这是默认值
})
// → '{\'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

indent 选项接受字符串值,默认为 '\t'。当 compact 设置禁用(false)时,indent 选项的值用于格式化输出。

jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
  compact: false,
  indent: '  '
})
// → '{\n  \'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}'

indentLevel

indentLevel 选项接受数值,默认为 0。它表示当前的缩进级别。

jsesc(['a', 'b', 'c'], {
  compact: false,
  indentLevel: 1
})
// → '[\n\t\t\'a\',\n\t\t\'b\',\n\t\t\'c\'\n\t]'

json

json 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,输出是有效的 JSON。

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

lowercaseHex 选项接受布尔值(truefalse),默认为 false(禁用)。启用时,转义序列中的任何字母十六进制数字都是小写的。

jsesc('Ich ♥ Bücher', {
  lowercaseHex: true
})
// → 'Ich \\u2665 B\\xfccher'
//                    ^^

jsesc(42, {
  numbers: 'hexadecimal',
  lowercaseHex: true
})
// → '0x2a'
//      ^^

版本信息

// 访问版本信息
import jsesc, { version } from 'jsesc-es'

console.log(jsesc.version) // 例如:"0.0.3"
console.log(version) // 例如:"0.0.3"

从 jsesc 迁移

从原始 jsesc 库迁移很简单:

1. 更新依赖

# 移除旧包
npm uninstall jsesc

# 安装新包
npm install jsesc-es

2. 更新导入

// 之前(CommonJS)
const jsesc = require('jsesc')

// 之后(ES 模块)
import jsesc from 'jsesc-es'

// 或带类型(TypeScript)
import jsesc, { type JsescOptions } from 'jsesc-es'

3. 享受增强功能

  • 完整的 TypeScript 支持 无需额外设置
  • 更好的 IDE 体验 包括 IntelliSense
  • 现代模块系统 支持 tree-shaking
  • 100% API 兼容 - 无需代码更改

详细的迁移说明,请参见 MIGRATION.md

TypeScript 示例

创建工具函数

import type { JsescOptions } from 'jsesc-es'
import jsesc from 'jsesc-es'

// 创建类型安全的工具函数
function createEscaper(defaultOptions: JsescOptions) {
  return (input: string, options?: Partial<JsescOptions>): string => {
    return jsesc(input, { ...defaultOptions, ...options })
  }
}

// 预配置的转义器
const escapeForHTML = createEscaper({
  quotes: 'double',
  wrap: true,
  isScriptContext: true
})

const escapeForJSON = createEscaper({
  json: true
})

const escapeMinimal = createEscaper({
  minimal: true
})

// 具有完整类型安全的使用
const htmlSafe = escapeForHTML('Hello "World"')
const jsonSafe = escapeForJSON({ message: 'Hello 世界' })
const minimalEscape = escapeMinimal('简单文本')

高级配置

import type { JsescOptions } from 'jsesc-es'

// 定义配置预设
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

// 类型安全的预设使用
function escapeWithPreset(
  input: any,
  preset: keyof typeof PRESETS,
  overrides?: Partial<JsescOptions>
): string {
  const config = { ...PRESETS[preset], ...overrides }
  return jsesc(input, config)
}

性能

jsesc-es 相比原版包含几项性能改进:

  • 优化的类型检查 提供更好的运行时性能
  • 改进的函数处理 增强的检测逻辑
  • 现代 JavaScript 特性 更好的引擎优化
  • 常见转义场景中的开销减少
  • Tree-shaking 支持 更小的包大小

浏览器支持

jsesc-es 通过其双构建系统提供广泛的兼容性:

运行时要求

对于 ES 模块(推荐):

  • Node.js:14+(原生 ESM 支持)
  • 浏览器:Chrome 61+、Firefox 60+、Safari 10.1+、Edge 16+
  • ES 模块:需要原生支持

对于 CommonJS(传统):

  • Node.js:6+(转译输出)
  • 浏览器:Chrome 27+、Firefox 3+、Safari 4+、Opera 10+(使用打包器)

构建目标 vs. 模块系统

虽然 jsesc-es 通过其转译的 CommonJS 构建保持与传统环境的兼容性(目标 node6、chrome27 等),ES 模块需要原生支持 import/export 语法的现代环境。构建目标确保 JavaScript 语法和 API 在较旧环境中工作,但 模块系统本身 有最低版本要求。

要点:

  • 📦 CommonJS 构建:在非常旧的环境中工作(Node 6+、Chrome 27+)
  • 🚀 ESM 构建:需要具有原生 ESM 支持的现代环境
  • 🔧 传统项目:使用 CommonJS 或使用 Babel/TypeScript 转译 ESM
  • 现代项目:使用 ESM 获得更好的 tree-shaking 和性能

TypeScript 支持

  • TypeScript:4.5+
  • 内置类型:无需 @types/

开发

# 克隆仓库
git clone https://github.com/Drswith/jsesc-es.git
cd jsesc-es

# 安装依赖
pnpm install

# 运行测试
pnpm test

# 构建项目
pnpm build

# 类型检查
pnpm typecheck

# 代码检查
pnpm lint

贡献

欢迎贡献!请阅读我们的贡献指南了解行为准则和提交拉取请求的流程详情。

许可证

本项目采用 MIT 许可证 - 详情请参见 LICENSE 文件。

致谢

  • Mathias Bynens - 原始 jsesc 库的创建者
  • TypeScript 团队 - 提供出色的工具和类型系统
  • 开源社区 - 持续的反馈和贡献

jsesc-es - 现代的、TypeScript 优先的 JavaScript 字符串转义方法。🚀