common-tags

A well-tested library of tagged template literal functions for cleaning up multiline strings, HTML, and lists in ES2015+ JavaScript.

Library
npm
v1.8.2
2,027stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
42/100Fair
Development Activity0
Maintenance20
Community48
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture82
Code Quality68
Innovation62
Learning Curve80

common-tags provides a collection of composable template literal tag functions that solve everyday string-formatting problems in JavaScript: stripping unwanted indentation from multiline strings, collapsing them onto one line, escaping HTML entities, and formatting comma-separated lists grammatically. Rather than hand-rolling regex or string-trimming logic for each case, developers import the specific tag they need — oneLine, stripIndent, html, safeHtml, commaListsAnd, and more — and apply it directly to a template literal.

Under the hood, every tag is built from the same createTag pipeline, which composes small transformer plugins that hook into the string-parsing, substitution, and end-result stages of tag evaluation. This design lets the library ship many purpose-built tags from a small set of reusable primitives, and it lets consumers build entirely new tags by combining the same transformers rather than writing parsing logic from scratch.

What You Get

  • A library of ready-made template tags (oneLine, stripIndent, html, safeHtml, codeBlock, commaLists, and more) covering the most common string-formatting needs
  • A createTag factory for composing custom tags out of reusable onString/onSubstitution/onEndResult transformer hooks
  • Automatic HTML-entity escaping via safeHtml to guard against injecting unescaped substitutions into markup
  • Grammar-aware list formatting tags (commaListsAnd, commaListsOr) that join array substitutions into readable comma-separated lists

Common Use Cases

  • Writing multiline SQL, GraphQL, or HTML template strings in source code without inheriting the file’s indentation
  • Collapsing a wrapped template literal into a single-line log message or CLI output with oneLine
  • Escaping substituted values in server-rendered HTML fragments with safeHtml to avoid XSS from unescaped user input
  • Formatting an array substitution into a natural-language list (‘a, b, and c’) with commaListsAnd inside error messages or UI copy

Under The Hood

Architecture common-tags is architected around a single core factory, src/createTag/index.js’s createTag, which every one of the ~20 exported tags (src/html, src/safeHtml, src/oneLine, src/stripIndent, src/commaLists, etc.) is built from by calling createTag(…transformers) with an ordered list of small transformer objects. Each transformer implements up to three optional hooks — onString, onSubstitution, and onEndResult — invoked at distinct stages of tag evaluation (per-literal-segment, per-substitution, and post-concatenation respectively), and createTag threads a per-call, per-transformer context object through each invocation via getInitialContext so stateful transformers (like stripIndentTransformer) don’t leak state across calls. Composability is structural, not just conventional: createTag recognizes when a nested tag is passed as the first template argument (getInterimTag) and flattens tag-of-tags compositions via a tagTransformersSymbol marker so that e.g. safeHtml is really stripIndent + inlineArrayTransformer + several replaceSubstitutionTransformer instances chained under one exported tag. This is a clean, low-coupling pipeline/middleware pattern — changing createTag’s hook contract would require updating every transformer file individually, but adding a new public tag never requires touching createTag itself, only composing existing transformers in src/<tagName>/<tagName>.js.

Tech Stack The library targets plain ES2015+ JavaScript with zero runtime dependencies; package.json’s only dependencies are devDependencies for the build/test toolchain — Babel 7 (@babel/core, @babel/preset-env, @babel/plugin-proposal-class-properties) transpiles src/ into three distinct output targets (lib/ as CommonJS, es/ as ES modules via a BABEL_ENV=es build, and a browser-ready dist/common-tags.min.js via Rollup with rollup-plugin-uglify, configured in rollup.config.js). Testing runs on Jest 26 (jest.config.js) with each tag’s *.test.js file colocated next to its implementation. Linting is ESLint 7 with eslint-config-prettier and eslint-plugin-prettier so Prettier formatting doubles as a lint rule, and CI is dual-tracked across Travis CI (.travis.yml, testing Node 10/12/13/14) and AppVeyor (appveyor.yml) with Codecov reporting via the codecov CLI package. There is no runtime framework, database, or server component — this is a pure string-processing utility library distributed to npm, unpkg, and jsDelivr.

Code Quality Every one of the ~20 tag modules has a colocated *.test.js file (33 test files against 65 non-test source files, roughly 1:2), and the core createTag.test.js file in particular is thorough — it covers hook-optionality, per-transformer context isolation, tag-of-tags composition order, plain-function invocation (non-template-literal calls), and even Symbol.toPrimitive coercion of substituted values via a mocked Proxy. Error handling is minimal but explicit where it exists (e.g. stripIndentTransformer throws a descriptive Error for an unsupported type argument rather than failing silently). Naming is consistent and self-documenting (stripIndentTransformer, replaceSubstitutionTransformer, splitStringTransformer), and most exported functions carry JSDoc comments describing parameters and return types, though there are no TypeScript type definitions bundled in the package. CI runs npm run lint && jest src on every push across two independent CI providers (Travis + AppVeyor) with Codecov coverage reporting, indicating quality gates are enforced, though the project has been dormant since its last commit in November 2021 with no further hardening since.

API Design The library’s core ergonomic idea is that every tag is just a plain tagged-template function — no class instantiation, no configuration object, just import { oneLine } from 'common-tags' and call it directly on a template literal, which keeps the public API surface essentially zero-boilerplate. The createTag composition model is the most distinctive design choice: rather than each tag reimplementing string-processing logic, they’re built from small, independently testable, single-purpose transformer functions (stripIndentTransformer, replaceSubstitutionTransformer, splitStringTransformer) that plug into three well-defined lifecycle hooks, and consumers get this same power for free — createTag is exported specifically so users can compose their own project-specific tags rather than being limited to the ~20 built-ins. This transformer-pipeline approach to template tag construction is not something most peer libraries expose, though the underlying technique (hook-based string transformation) is a fairly standard middleware pattern applied to a narrow domain rather than a genuinely novel algorithm.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search