Safe Identifier String Sanitization
safe-identifier is a focused utility library designed to sanitize arbitrary strings for safe use as JavaScript identifiers and object property names. It currently stands at version 0.4.2 and has shown an active release cadence, with several minor versions released recently. The library's core functionality includes replacing invalid characters with underscores, pre-pending an underscore if the resulting identifier conflicts with a JavaScript reserved word (covering ES3 to ES2018 and active proposals), and optionally appending a unique hash to generated identifiers. For property names, it intelligently uses dot notation (`obj.key`) or bracket notation (`obj["key"]`) based on key validity and ECMAScript 3rd Edition reserved words, ensuring compatibility down to IE8. Its primary differentiator is its comprehensive standard coverage and explicit handling for browser compatibility and uniqueness.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module .../node_modules/safe-identifier/index.js from ... not supported.
cause Attempting to `require()` the `safe-identifier` package in a CommonJS module after v0.4.0, which transitioned to an ESM-first package structure.fixChange your import statement from `const { identifier } = require('safe-identifier');` to `import { identifier } from 'safe-identifier';` and ensure your project is configured for ESM. -
TypeError: identifier is not a function
cause Incorrectly importing or destructuring `identifier` or `property`, possibly due to a mixed CommonJS/ESM environment or a typo.fixVerify that you are using the correct import syntax for your module type (e.g., `import { identifier } from 'safe-identifier';` for ESM) and that `safe-identifier` is correctly installed in your `node_modules`. -
The output of identifier('my_input', true) is not consistent between runs or environments.cause The `unique` parameter for `identifier` appends a hash, which is designed to vary based on the input key's hash and potentially other factors, making the output non-deterministic for the same 'base' string.fixIf you require a consistent, deterministic output for a given input string, ensure you do not pass `true` as the second argument to `identifier`. Only use `unique: true` when you need to avoid name collisions.
Warnings
- breaking Version 0.4.0 introduced `exports` and `type: module` fields to `package.json`, and dropped the separate `reserved.mjs` file. This change makes the package ESM-first and can cause issues with CommonJS `require()` in environments that strictly enforce module resolution.
- breaking The `identifier` function's signature changed in v0.3.0 to add a second optional boolean argument `unique`. While an addition, it's important to be aware if you had custom wrappers or type definitions that assumed a single argument.
- gotcha The `unique` parameter for `identifier(key, unique)` appends a 32-bit hash of the original `key` to the sanitized output. If `unique` is set to `true`, the output will always vary for different inputs or even the same input if an internal hash salt were to change (though unlikely in this lib).
- gotcha The `property` function applies specific rules for ECMAScript 3rd Edition reserved words (e.g., `void`, `enum`) and invalid characters, potentially quoting the key, to ensure compatibility with older browsers like IE8. This might result in a more verbose property access string than strictly necessary for modern environments.
Install
-
npm install safe-identifier -
yarn add safe-identifier -
pnpm add safe-identifier
Imports
- identifier
const identifier = require('safe-identifier').identifierimport { identifier } from 'safe-identifier' - property
const property = require('safe-identifier/dist/property.js')import { property } from 'safe-identifier' - All exports
const safeIdentifier = require('safe-identifier')import * as safeIdentifier from 'safe-identifier'
Quickstart
import { identifier, property } from 'safe-identifier';
// Basic identifier sanitization
console.log(`'Foo' -> ${identifier('Foo')}`); // 'Foo'
console.log(`'enum' (reserved word) -> ${identifier('enum')}`); // '_enum'
// Identifier with uniqueness hash
const keyWithSpaces = 'my var';
const uniqueId1 = identifier(keyWithSpaces, true);
const uniqueId2 = identifier(' another\tkey ', true);
console.log(`'${keyWithSpaces}' (unique) -> ${uniqueId1}`); // Example: 'my_var_hk17pp'
console.log(`' another\tkey ' (unique) -> ${uniqueId2}`); // Example: 'another_key_1d8fi3'
// Property name sanitization
console.log(`'Foo', 'bar' -> ${property('Foo', 'bar')}`); // 'Foo.bar'
console.log(`'Foo', 'bar\nbar' -> ${property('Foo', 'bar\nbar')}`); // 'Foo["bar\nbar"]'
console.log(`null, 'foo' -> ${property(null, 'foo')}`); // 'foo'
console.log(`null, 'void' (ES3 reserved) -> ${property(null, 'void')}`); // '"void"' (quoted for ES3 compatibility)