mrkeyoor.com_
Sat 08 Aug 21:01 UTC
npmUtilsupdated 08 Aug 2026

trim-repeated

trim-repeated is a tiny JavaScript string utility that reduces consecutive copies of an exact substring to one copy. Give it an input such as `foo---bar` and the target `-`, and it returns `foo-bar`; targets may also contain several characters, punctuation, backslashes, or emoji. Version 2 exposes one default function as an ES module and supports Node.js 12 or newer. It is literal text cleanup, not whitespace normalization, fuzzy matching, or a general parser.

Verdict

A correct, readable one-function package for collapsing an exact repeated delimiter, particularly when the delimiter contains regex syntax. Do not add it for whitespace-only cleanup, synchronous CommonJS, or strict TypeScript without planning for its missing declarations and quiet maintenance history.

API stability4/5The entire public API is one default function with two required string arguments, and the repository tests literal punctuation, backslashes, emoji, and multi-character targets. Only two versions have been published since 2015, which keeps the surface predictable. The main compatibility break was version 2 moving to ESM-only packaging and Node.js 12 or newer, so consumers crossing that major cannot assume require() still works.
Docs3/5The README states the purpose, installation command, default import, signature, argument types, and examples for both one-character and multi-character targets. That is enough to use such a small function correctly. It does not document ESM migration, missing TypeScript declarations, empty-target behavior, performance characteristics, thrown-error details, or edge cases that are visible only in the source and tests.
Maintenance2/5The repository is not archived and currently reports zero open issues and pull requests, but the latest npm release, 2.0.0, dates to April 2021 and the last repository push was July 2022. A nine-line implementation may genuinely need little activity, yet its sole dependency and runtime compatibility will not update themselves. Treat the calm history as low maintenance demand, not proof of active stewardship.
Ecosystem3/5The package recorded 5,161,497 downloads in the npm last-week endpoint, so it is widely present despite only 21 GitHub stars. It uses a familiar Sindre Sorhus ESM style and depends only on escape-string-regexp. Ecosystem fit is reduced by the lack of bundled TypeScript declarations, no CommonJS export in version 2, and no plugin or integration layer beyond the one function.

Use it if

  • You need to collapse consecutive copies of one known delimiter while leaving every other character untouched
  • Your target can contain regular-expression characters and you want the package to escape them correctly
  • You need multi-character targets such as `@#`, which are more awkward to express with a quick character-class regex
  • You already ship ES modules and value a named, tested operation over repeating a custom regex across the codebase
Skip it if

Setup reality

Installation is one command, `npm install trim-repeated`, and there are no peer dependencies, credentials, native extensions, or configuration files. The important compatibility detail is packaging: version 2 is ESM-only, requires Node.js 12 or newer, and exposes a default export. An ES module can use `import trimRepeated from 'trim-repeated'`; older CommonJS code cannot use a synchronous `require('trim-repeated')` and must either switch module formats, use dynamic `import()`, or stay on an older line with its own maintenance tradeoffs. The package has one runtime dependency, `escape-string-regexp`, because it builds a global regular expression for the supplied target. That escaping means targets such as `.`, `\`, `)`, or `@#` are treated literally. Both arguments must be strings or the function throws `TypeError: Expected a string`; it does not coerce numbers, buffers, null, or arrays. There are no published TypeScript declarations in version 2, so TypeScript users may see a missing-declaration error under strict settings and need a local `declare module` shim. The function creates a new regular expression on every call, so code processing a very hot loop with the same delimiter may be better served by a precompiled local regex. It only collapses adjacent, exact, case-sensitive copies. It does not trim the target from either end, normalize Unicode, remove isolated targets, or understand delimiter structure such as the `//` in a URL. Validate untrusted targets before calling it, especially an empty string, because the public contract merely says the target is a required string and does not promise useful empty-target behavior.

Patterns

Collapse repeated hyphenscollapse-hyphens

import trimRepeated from 'trim-repeated';

const value = trimRepeated('foo--bar---baz', '-');
// 'foo-bar-baz'

Every run of two or more adjacent hyphens becomes one; isolated hyphens remain unchanged.

Collapse a repeated multi-character delimitercollapse-multi-character-target

import trimRepeated from 'trim-repeated';

const value = trimRepeated('foo@#@#@#baz', '@#');
// 'foo@#baz'

The target is a complete substring, not a character class, so each adjacent `@#` pair must line up exactly.

Treat regular-expression syntax literallycollapse-regex-symbol

const value = trimRepeated('part....next', '.');
// 'part.next'

The dependency escape-string-regexp escapes the target before the package constructs its global regular expression.

Collapse repeated backslashescollapse-backslashes

const value = trimRepeated(String.raw`foo\\bar`, '\');
// 'foo\bar'

JavaScript string escaping still applies; String.raw makes the input easier to read when backslashes are the data.

Collapse an exact repeated emojicollapse-emoji

const value = trimRepeated('ready🐴🐴🐴done', '🐴');
// 'ready🐴done'

The repository test suite covers this exact kind of emoji target, though the package performs no broader Unicode normalization.

Leave nonconsecutive targets alonepreserve-separated-targets

const value = trimRepeated('one--two-x--three', '--');
// 'one--two-x--three'

A target must appear twice back-to-back before anything changes; a single occurrence is preserved.

Clean every repeated run in one callcollapse-throughout-string

const value = trimRepeated('a:::b:::::c:::d', ':');
// 'a:b:c:d'

The implementation uses a global regular expression, so it replaces every qualifying run rather than only the first.

Validate an externally supplied targetvalidate-external-input

function collapse(input, target) {
  if (typeof input !== 'string' || typeof target !== 'string' || target.length === 0) {
    throw new TypeError('input and non-empty target must be strings');
  }
  return trimRepeated(input, target);
}

The package checks only that both values are strings; add the non-empty rule when callers can choose the target.

Load version 2 from CommonJSuse-from-commonjs

async function clean(value) {
  const { default: trimRepeated } = await import('trim-repeated');
  return trimRepeated(value, '_');
}

clean('a___b').then(console.log);

Version 2 is ESM-only, so CommonJS must use asynchronous dynamic import; synchronous require() is not supported.

Add a local TypeScript declarationadd-typescript-shim

// types/trim-repeated.d.ts
declare module 'trim-repeated' {
  export default function trimRepeated(input: string, target: string): string;
}

Version 2 does not publish declarations. Include the folder in tsconfig if TypeScript does not discover the shim automatically.

Collapse a generated slug delimiternormalize-generated-slug

const rough = 'open---source--guide';
const slug = trimRepeated(rough, '-').replace(/^-|-$/g, '');
// 'open-source-guide'

The package collapses repeats but does not remove leading or trailing delimiters, so edge trimming remains a separate step.

Limit slash cleanup to a URL pathavoid-url-corruption

const url = new URL('https://example.com//docs///api');
url.pathname = trimRepeated(url.pathname, '/');
// https://example.com/docs/api

Do not run slash collapsing over a complete URL string, because it would also reduce the `//` after the protocol.

Alternatives

PackageRegistryPick it when
condense-whitespacenpmChoose it when the actual job is trimming and collapsing whitespace rather than an arbitrary substring
collapse-white-spacenpmChoose it for a focused whitespace collapse helper that works on text with mixed whitespace characters
lodashnpmChoose it only when Lodash is already in the application and a local replace expression avoids another package