A Babel plugin that escapes U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR characters in JavaScript string literals and directive literals to prevent syntax errors when JSON strings containing these characters are embedded in JavaScript code.
npm install --save-dev @babel/plugin-transform-json-stringsESM import:
import transformJsonStrings from "@babel/plugin-transform-json-strings";CommonJS require:
const transformJsonStrings = require("@babel/plugin-transform-json-strings");Add the plugin to your Babel configuration:
{
"plugins": ["@babel/plugin-transform-json-strings"]
}Or with explicit import:
import { transform } from "@babel/core";
import transformJsonStrings from "@babel/plugin-transform-json-strings";
const result = transform(code, {
plugins: [transformJsonStrings]
});Input JavaScript:
// Note: The actual Unicode characters are represented as comments
// since they may not display properly in documentation
const message = "Hello world"; // Contains actual U+2028 between "Hello" and "world"
"use strict"; // Contains actual U+2029 at the endOutput JavaScript:
const message = "Hello\u2028world"; // U+2028 escaped as \u2028
"use strict\u2029"; // U+2029 escaped as \u2029Based on the plugin's test cases, here are more complex transformation scenarios:
Handling Multiple Backslashes:
// Input (with actual U+2028 characters represented in comments)
"\\ " // Two backslashes + U+2028
"\\\ " // Three backslashes + U+2028
// Output
"\\\u2028" // Even backslashes: escape the separator
"\\\ " // Odd backslashes: separator already escaped, unchangedThe main and only export is a Babel plugin function created using the @babel/helper-plugin-utils declare utility.
/**
* Babel plugin created with @babel/helper-plugin-utils declare utility
* that transforms string and directive literals containing Unicode separators
* @param api - Babel API object with assertVersion method
* @returns Babel plugin configuration object
*/
function transformJsonStrings(api: BabelAPI): BabelPlugin;
// Default export created by declare() utility
export default transformJsonStrings;
interface BabelAPI {
/** Assert minimum Babel version compatibility */
assertVersion(version: number): void;
}
interface BabelPlugin {
/** Plugin name identifier */
name: "transform-json-strings";
/** Optional parser configuration handler (undefined in BABEL_8_BREAKING mode) */
manipulateOptions?: (opts: any, parser: ParserOptions) => void;
/** AST visitor for transforming string literals */
visitor: BabelVisitor;
}
interface ParserOptions {
/** Array of parser plugins to enable */
plugins: string[];
}
interface BabelVisitor {
/** Visitor method for DirectiveLiteral and StringLiteral nodes */
"DirectiveLiteral|StringLiteral"(path: NodePath<DirectiveLiteral | StringLiteral>): void;
}
interface NodePath<T> {
/** AST node being visited */
node: T;
}
interface DirectiveLiteral {
/** Additional node metadata including raw source text */
extra?: {
/** Original raw string from source code */
raw?: string;
};
}
interface StringLiteral {
/** Additional node metadata including raw source text */
extra?: {
/** Original raw string from source code */
raw?: string;
};
}The plugin returns a configuration object with the following properties:
name: "transform-json-strings"The identifier used by Babel to reference this plugin.
manipulateOptions?: (opts: any, parser: any) => voidWhen not in BABEL_8_BREAKING mode, this function adds the "jsonStrings" parser plugin to enable parsing of JSON strings. This property is undefined in BABEL_8_BREAKING mode.
visitor: {
"DirectiveLiteral|StringLiteral"(path: NodePath<DirectiveLiteral | StringLiteral>): void;
}The visitor object contains a single method that processes both DirectiveLiteral nodes (like "use strict") and StringLiteral nodes (regular string literals) in the AST.
The plugin specifically targets two Unicode characters that can cause JavaScript syntax errors:
\u2028\u2029The plugin uses a regular expression to find Unicode separators and a replacement function to handle escaping:
/** Regular expression matching Unicode separators with preceding backslashes */
const regex: RegExp; // /(\\*)([\u2028\u2029])/g
/**
* Replacement function for handling escape logic
* @param match - Full regex match
* @param escapes - Captured backslashes preceding the separator
* @param separator - The Unicode separator character
* @returns Properly escaped string or original match if already escaped
*/
function replace(match: string, escapes: string, separator: string): string;The plugin intelligently handles existing escape sequences:
"Hello world" → "Hello\u2028world""Hello\u2028world" → "Hello\u2028world" (unchanged)"Hello\\ world" → "Hello\\\u2028world"extra.raw: The plugin only transforms string literals that have the original raw source text availableinterface Dependencies {
"@babel/helper-plugin-utils": "workspace:^";
}The plugin uses @babel/helper-plugin-utils for the declare utility function and version assertion.
interface PeerDependencies {
"@babel/core": "^7.0.0-0";
}This plugin requires Babel core version 7.0.0 or higher as a peer dependency.
interface EngineRequirements {
/** Node.js version requirement */
node: ">=6.9.0" | "^20.19.0 || >=22.12.0"; // Latter for BABEL_8_BREAKING
}The plugin supports Node.js 6.9.0 and higher, with stricter requirements in BABEL_8_BREAKING mode.