├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .npmrc ├── index.d.ts ├── index.js ├── index.test-d.ts ├── license ├── package.json ├── readme.md └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - push 4 | - pull_request 5 | jobs: 6 | test: 7 | name: Node.js ${{ matrix.node-version }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | node-version: 13 | - 20 14 | - 18 15 | - 16 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | - run: npm install 22 | - run: npm test 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Encode Unicode characters in a string to Unicode escapes. 3 | 4 | @param string - The string to be encoded. 5 | @return The encoded string. 6 | 7 | @example 8 | ``` 9 | import {encodeUnicodeEscapes} from 'unicode-escapes'; 10 | 11 | console.log(encodeUnicodeEscapes('Hello, โลก')); 12 | //=> 'Hello, \u{e42}\u{e25}\u{e01}' 13 | ``` 14 | */ 15 | export function encodeUnicodeEscapes(string: string): string; 16 | 17 | /** 18 | Decode Unicode escapes in a string to Unicode characters. 19 | 20 | @param string - The string to be decoded. 21 | @return The decoded string. 22 | 23 | @example 24 | ``` 25 | import {decodeUnicodeEscapes} from 'unicode-escapes'; 26 | 27 | console.log(decodeUnicodeEscapes('Hello, \\u{e42}\\u{e25}\\u{e01}')); 28 | //=> 'Hello, โลก' 29 | ``` 30 | */ 31 | export function decodeUnicodeEscapes(string: string): string; 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const isASCII = character => character.codePointAt(0) <= 127; 2 | 3 | const validateString = string => { 4 | if (typeof string !== 'string') { 5 | throw new TypeError(`Expected a string, got \`${typeof string}\`.`); 6 | } 7 | }; 8 | 9 | export function encodeUnicodeEscapes(string) { 10 | validateString(string); 11 | 12 | return [...string] 13 | .map(character => isASCII(character) ? character : `\\u{${character.codePointAt(0).toString(16)}}`) 14 | .join(''); 15 | } 16 | 17 | export function decodeUnicodeEscapes(string) { 18 | validateString(string); 19 | 20 | return string.replaceAll(/\\u{([\da-f]{1,6})}|\\u([\da-f]{4})/gi, (_, p1, p2) => String.fromCodePoint(Number.parseInt(p1 ?? p2, 16))); 21 | } 22 | -------------------------------------------------------------------------------- /index.test-d.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import {encodeUnicodeEscapes, decodeUnicodeEscapes} from './index.js'; 3 | 4 | expectType(encodeUnicodeEscapes('')); 5 | expectType(decodeUnicodeEscapes('')); 6 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unicode-escapes", 3 | "version": "1.0.0", 4 | "description": "Encode and decode Unicode escapes in a string", 5 | "license": "MIT", 6 | "repository": "sindresorhus/unicode-escapes", 7 | "funding": "https://github.com/sponsors/sindresorhus", 8 | "author": { 9 | "name": "Sindre Sorhus", 10 | "email": "sindresorhus@gmail.com", 11 | "url": "https://sindresorhus.com" 12 | }, 13 | "type": "module", 14 | "exports": { 15 | "types": "./index.d.ts", 16 | "default": "./index.js" 17 | }, 18 | "engines": { 19 | "node": ">=16" 20 | }, 21 | "scripts": { 22 | "test": "xo && ava && tsd" 23 | }, 24 | "files": [ 25 | "index.js", 26 | "index.d.ts" 27 | ], 28 | "keywords": [ 29 | "unicode", 30 | "escape", 31 | "escapes", 32 | "encode", 33 | "decode", 34 | "character", 35 | "string", 36 | "debugging", 37 | "logging", 38 | "text-processing", 39 | "data-sanitization" 40 | ], 41 | "devDependencies": { 42 | "ava": "^5.3.1", 43 | "tsd": "^0.28.1", 44 | "xo": "^0.56.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # unicode-escapes 2 | 3 | > Encode and decode [Unicode escapes](https://mathiasbynens.be/notes/javascript-escapes#unicode-code-point) in a string 4 | 5 | Can be useful when a tool or service returns text with encoded Unicode characters. 6 | 7 | ## Install 8 | 9 | ```sh 10 | npm install unicode-escapes 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```js 16 | import {encodeUnicodeEscapes, decodeUnicodeEscapes} from 'unicode-escapes'; 17 | 18 | console.log(encodeUnicodeEscapes('Hello, โลก')); 19 | //=> 'Hello, \u{e42}\u{e25}\u{e01}' 20 | 21 | console.log(decodeUnicodeEscapes('Hello, \\u{e42}\\u{e25}\\u{e01}')); 22 | //=> 'Hello, โลก' 23 | ``` 24 | 25 | ## API 26 | 27 | ### encodeUnicodeEscapes(string) 28 | 29 | Encode Unicode characters in a string to Unicode escapes. 30 | 31 | ### decodeUnicodeEscapes(string) 32 | 33 | Decode Unicode escapes in a string to Unicode characters. 34 | 35 | ## Use-cases 36 | 37 | - **Debugging and logging:** Encoding and decoding Unicode escapes can be valuable in debugging scenarios, where you might need to inspect strings with non-visible or special characters. It can assist in displaying logs, traces, or debug outputs that are human-readable. 38 | - **Data serialization and deserialization:** Ensuring consistent representation of Unicode characters when saving and reading data, particularly in formats that may have special handling for certain escape sequences. 39 | - **Source code analysis and manipulation:** For tooling that analyzes or manipulates source code, such as linters or code transformation tools, where representing characters in escape sequences might be necessary. 40 | - **Interoperability with legacy systems:** When interacting with systems that expect a particular escape syntax for Unicode characters. 41 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import {encodeUnicodeEscapes, decodeUnicodeEscapes} from './index.js'; 3 | 4 | test('encodeUnicodeEscapes', t => { 5 | t.is(encodeUnicodeEscapes('你好'), '\\u{4f60}\\u{597d}'); 6 | }); 7 | 8 | test('encodeUnicodeEscapes - ASCII remains unchanged', t => { 9 | t.is(encodeUnicodeEscapes('Hello World!'), 'Hello World!'); 10 | }); 11 | 12 | test('encodeUnicodeEscapes - mix Unicode and ASCII', t => { 13 | t.is(encodeUnicodeEscapes('Hello 你好 World!'), 'Hello \\u{4f60}\\u{597d} World!'); 14 | }); 15 | 16 | test('decodeUnicodeEscapes - modern syntax', t => { 17 | t.is(decodeUnicodeEscapes('\\u{4F60}\\u{597D}'), '你好'); 18 | }); 19 | 20 | test('decodeUnicodeEscapes - old syntax', t => { 21 | t.is(decodeUnicodeEscapes('\\u4F60\\u597D'), '你好'); 22 | }); 23 | 24 | test('decodeUnicodeEscapes - handles mix of modern and old syntax', t => { 25 | t.is(decodeUnicodeEscapes('\\u{4F60}\\u597D'), '你好'); 26 | }); 27 | 28 | test('decodeUnicodeEscapes - handles modern syntax with different lengths', t => { 29 | t.is(decodeUnicodeEscapes('\\u{A}\\u{4F60}\\u{1F600}'), '\u{A}\u{4F60}\u{1F600}'); 30 | }); 31 | 32 | test('decodeUnicodeEscapes - ignores invalid modern syntax with too many characters', t => { 33 | t.is(decodeUnicodeEscapes('\\u{1234567}'), '\\u{1234567}'); 34 | }); 35 | --------------------------------------------------------------------------------