Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
common-tags
Advanced tools
The common-tags npm package provides utility functions for manipulating and using template literals in JavaScript. It offers a variety of tagged template literals for tasks such as stripping indentation, creating multiline strings, and formatting strings with data.
Strip Indentation
Strips leading indentation from multiline strings, making it easier to work with template literals without worrying about the formatting in the source code.
`
This is a string
that has inconsistent
indentation.
`
One Line
Converts a multiline string into a single line, removing all newline characters. Useful for creating single-line strings from template literals that span multiple lines in the source code.
`This is a
multiline string
that will be converted
to a single line.`
Safe HTML
Escapes HTML to prevent XSS attacks when injecting user-generated content into the DOM. This feature ensures that strings are safely encoded.
`<div>${unsafeVariable}</div>`
Similar to the strip indentation feature of common-tags, dedent is focused solely on removing excess indentation from template strings. It's a more lightweight option if indentation stripping is the only requirement.
Offers functionality for manipulating and using template literals, similar to common-tags. However, it might have a different set of utilities or implementations, providing an alternative approach to handling template strings.
π A set of well-tested, commonly used template literal tag functions for use in ES2015+.
π Plus some extra goodies for easily making your own tags.
import { html } from 'common-tags';
html`
<div id="user-card">
<h2>${user.name}</h2>
</div>
`
Info | Badges |
---|---|
Version | |
License | |
Popularity | |
Testing | |
Quality | |
Style |
common-tags
common-tags
initially started out as two template tags I'd always find myself writing - one for stripping indents, and one for trimming multiline strings down to a single line. In it's prime, I was an avid user of CoffeeScript, which had this behaviour by default as part of it's block strings feature. I also started out programming in Ruby, which has a similar mechanism called Heredocs.
Over time, I found myself needing a few more template tags to cover edge cases - ones that supported including arrays, or ones that helped to render out tiny bits of HTML not large enough to deserve their own file or an entire template engine. So I packaged all of these up into this module.
As more features were proposed, and I found myself needing a way to override the default settings to cover even more edge cases, I realized that my initial implementation wouldn't be easy to scale.
So I re-wrote this module on top of a core architecture that makes use of transformer plugins which can be composed, imported independently and re-used.
Tagged templates in ES2015 are a welcome feature. But, they have their downsides. One such downside is that they preserve all whitespace by default - which makes multiline strings in source code look terrible.
Source code is not just for computers to interpret. Humans have to read it too π. If you care at all about how neat your source code is, or come from a CoffeeScript background and miss the block string syntax, then you will love common-tags
, as it was initially intended to bring this feature "back" to JS since it's initial commit.
common-tags
also exposes a means of composing pipelines of dynamic transformer plugins. As someone with a little experience writing tagged templates, I can admit that it is often the case that one tag might need to do the same thing as another tag before doing any further processing; for example - a typical tag that renders out HTML could strip initial indents first, then worry about handling character escapes. Both steps could easily be useful as their own separate template tags, but there isn't an immediately obvious way of composing the two together for maximum re-use. common-tags
offers not one, but two ways of doing this.
Furthermore, I try to keep this project as transparently stable and updated as frequently as I possibly can. As you may have already seen by the project status table, common-tags
is linted, well tested, tests are well covered, tests pass on both Unix and Windows operating systems, the popularity bandwidth is easily referenced and dependency health is in plain sight π. common-tags
is also already used in production on a number of proprietary sites and dependent projects, and contributions are always welcome, as are suggestions.
common-tags
The official recommendation for running common-tags
is as follows:
common-tags
, your environment will also need to support ES2015 tagged templates (pssst⦠check Babel out)Array.prototype.includes
It might work with below versions of Node, but this is not a guarantee.
common-tags
is a Node module. So, as long as you have Node.js and NPM installed, installing common-tags
is as simple as running this in a terminal at the root of your project:
npm install common-tags
common-tags
is also available at unpkg. Just put this code in your HTML:
<script src="https://unpkg.com/common-tags"></script>
This will make the library available under a global variable commonTags
.
Like all modules, common-tags
begins with an import
. In fact, common-tags
supports two styles of import:
Named imports:
import {stripIndent} from 'common-tags'
Direct module imports:
(Useful if your bundler doesn't support tree shaking but you still want to only include modules you need).
import stripIndent from 'common-tags/lib/stripIndent'
common-tags
exports a bunch of wonderful pre-cooked template tags for your eager consumption. They are as follows:
html
source
, codeBlock
You'll often find that you might want to include an array in a template. Typically, doing something like ${array.join(', ')}
would work - but what if you're printing a list of items in an HTML template and want to maintain the indentation? You'd have to count the spaces manually and include them in the .join()
call - which is a bit ugly for my taste. This tag properly indents arrays, as well as newline characters in string substitutions, by converting them to an array split by newline and re-using the same array inclusion logic:
import {html} from 'common-tags'
let fruits = ['apple', 'orange', 'watermelon']
html`
<div class="list">
<ul>
${fruits.map(fruit => `<li>${fruit}</li>`)}
${'<li>kiwi</li>\n<li>guava</li>'}
</ul>
</div>
`
Outputs:
<div class="list">
<ul>
<li>apple</li>
<li>orange</li>
<li>watermelon</li>
<li>kiwi</li>
<li>guava</li>
</ul>
</div>
safeHtml
A tag very similar to html
but it does safe HTML escaping for strings coming from substitutions. When combined with regular html
tag, you can do basic HTML templating that is safe from XSS (Cross-Site Scripting) attacks.
import {html, safeHtml} from 'common-tags'
let userMessages = ['hi', 'what are you up to?', '<script>alert("something evil")</script>']
html`
<div class="chat-list">
<ul>
${userMessages.map(message => safeHtml`<li>${message}</li>`)}
</ul>
</div>
`
Outputs:
<div class="chat-list">
<ul>
<li>hi</li>
<li>what are you up to?</li>
<li><script>alert("something evil")</script></li>
</ul>
</div>
oneLine
Allows you to keep your single-line strings under 80 characters without resorting to crazy string concatenation.
import {oneLine} from 'common-tags'
oneLine`
foo
bar
baz
`
// "foo bar baz"
oneLineTrim
Allows you to keep your single-line strings under 80 characters while trimming the new lines:
import {oneLineTrim} from 'common-tags'
oneLineTrim`
https://news.com/article
?utm_source=designernews.co
`
// https://news.com/article?utm_source=designernews.co
stripIndent
If you want to strip the initial indentation from the beginning of each line in a multiline string:
import {stripIndent} from 'common-tags'
stripIndent`
This is a multi-line string.
You'll ${verb} that it is indented.
We don't want to output this indentation.
But we do want to keep this line indented.
`
// This is a multi-line string.
// You'll notice that it is indented.
// We don't want to output this indentation.
// But we do want to keep this line indented.
Important note: this tag will not indent multiline strings coming from the substitutions. If you want that behavior, use the html
tag (aliases: source
, codeBlock
).
stripIndents
If you want to strip all of the indentation from the beginning of each line in a multiline string:
import {stripIndents} from 'common-tags'
stripIndents`
This is a multi-line string.
You'll ${verb} that it is indented.
We don't want to output this indentation.
We don't want to keep this line indented either.
`
// This is a multi-line string.
// You'll notice that it is indented.
// We don't want to output this indentation.
// We don't want to keep this line indented either.
inlineLists
Allows you to inline an array substitution as a list:
import {inlineLists} from 'common-tags'
inlineLists`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples bananas watermelons
// They're good!
oneLineInlineLists
Allows you to inline an array substitution as a list, rendered out on a single line:
import {oneLineInlineLists} from 'common-tags'
oneLineInlineLists`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples bananas watermelons They're good!
commaLists
Allows you to inline an array substitution as a comma-separated list:
import {commaLists} from 'common-tags'
commaLists`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples, bananas, watermelons
// They're good!
commaListsOr
Allows you to inline an array substitution as a comma-separated list, the last of which is preceded by the word "or":
import {commaListsOr} from 'common-tags'
commaListsOr`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples, bananas or watermelons
// They're good!
commaListsAnd
Allows you to inline an array substitution as a comma-separated list, the last of which is preceded by the word "and":
import {commaListsAnd} from 'common-tags'
commaListsAnd`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples, bananas and watermelons
// They're good!
oneLineCommaLists
Allows you to inline an array substitution as a comma-separated list, and is rendered out on to a single line:
import {oneLineCommaLists} from 'common-tags'
oneLineCommaLists`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples, bananas or watermelons They're good!
oneLineCommaListsOr
Allows you to inline an array substitution as a comma-separated list, the last of which is preceded by the word "or", and is rendered out on to a single line:
import {oneLineCommaListsOr} from 'common-tags'
oneLineCommaListsOr`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples, bananas or watermelons They're good!
oneLineCommaListsAnd
Allows you to inline an array substitution as a comma-separated list, the last of which is preceded by the word "and", and is rendered out on to a single line:
import {oneLineCommaListsAnd} from 'common-tags'
oneLineCommaListsAnd`
I like ${['apples', 'bananas', 'watermelons']}
They're good!
`
// I like apples, bananas and watermelons They're good!
It's possible to pass the output of a tagged template to another template tag in pure ES2015+:
import {oneLine} from 'common-tags'
oneLine`
${String.raw`
foo
bar\nbaz
`}
`
// "foo bar\nbaz"
We can make this neater. Every tag common-tags
exports can delay execution if it receives a function as it's first argument. This function is assumed to be a template tag, and is called via an intermediary tagging process before the result is passed back to our tag. Use it like so (this code is equivalent to the previous code block):
import {oneLine} from 'common-tags'
oneLine(String.raw)`
foo
bar\nbaz
`
// "foo bar\nbaz"
Sometimes you might want to use a tag on a normal string (e.g. for stripping the indentation). For that purpose just call a tag as a function with the passed string:
import {stripIndent} from 'common-tags'
stripIndent(" foo\n bar")
// "foo\n bar"
There are third-party type definitions for common-tags
on npm. Just install them like so:
npm install @types/common-tags
Please note that these type definitions are not officially maintained by the authors of
common-tags
- they are maintained by the TypeScript community.
common-tags
exposes an interface that allows you to painlessly create your own template tags.
common-tags
exports a TemplateTag
class. This class is the foundation of common-tags
. The concept of the class works on the premise that transformations occur on a template either when the template is finished being processed (onEndResult
), or when the tag encounters a string (onString
) or a substitution (onSubstitution
). Any tag produced by this class supports tail processing.
The easiest tag to create is a tag that does nothing:
import {TemplateTag} from 'common-tags'
const doNothing = new TemplateTag()
doNothing`foo bar`
// 'foo bar'
TemplateTag
receives either an array or argument list of transformers
. A transformer
is just a plain object with three optional methods - onString
, onSubstitution
and onEndResult
- it looks like this:
{
onString (str) {
// optional. Called when the tag encounters a string.
// (a string is whatever's not inside "${}" in your template literal)
// `str` is the value of the current string
},
onSubstitution (substitution, resultSoFar) {
// optional. Called when the tag encounters a substitution.
// (a substitution is whatever's inside "${}" in your template literal)
// `substitution` is the value of the current substitution
// `resultSoFar` is the end result up to the point of this substitution
},
onEndResult (endResult) {
// optional. Called when all substitutions have been parsed
// `endResult` is the final value.
}
}
You can wrap a transformer in a function that receives arguments in order to create a dynamic plugin:
const substitutionReplacer = (oldValue, newValue) => ({
onSubstitution(substitution, resultSoFar) {
if (substitution === oldValue) {
return newValue
}
return substitution
}
})
const replaceFizzWithBuzz = new TemplateTag(substitutionReplacer('fizz', 'buzz'))
replaceFizzWithBuzz`foo bar ${"fizz"}`
// "foo bar buzz"
note - if you call
new TemplateTag(substitutionReplacer)
,substitutionReplacer
will automatically be initiated with no arguments.
You can pass a list of transformers, and TemplateTag
will call them on your tag in the order they are specified:
// note: passing these as an array also works
const replace = new TemplateTag(
substitutionReplacer('fizz', 'buzz'),
substitutionReplacer('foo', 'bar')
)
replace`${"foo"} ${"fizz"}`
// "bar buzz"
When multiple transformers are passed to TemplateTag
, they will be iterated three times - first, all transformer onString
methods will be called. Once they are done processing, onSubstitution
methods will be called. Finally, all transformer onEndResult
methods will be called.
This is super easy. Transformers are just objects, after all. They have full access to this
:
const listSubs = {
onString(str) {
this.ctx = this.ctx || { strings: [], subs: [] }
this.ctx.strings.push(str);
return str
},
onSubstitution(sub, res) {
this.ctx.subs.push({ sub, precededBy: res })
return sub
},
onEndResult(res) {
return this.ctx
}
}
const toJSON = {
onEndResult(res) {
return JSON.stringify(res, null, 2)
}
}
const log = {
onEndResult(res) {
console.log(res)
return res
}
}
const process = new TemplateTag([listSubs, toJSON, log])
process`
foo ${'bar'}
fizz ${'buzz'}
`
// {
// "strings": [
// "\n foo ",
// "\n foo bar\n fizz ",
// "\n"
// ],
// "subs": [
// {
// "sub": "bar",
// "precededBy": "\n foo "
// },
// {
// "sub": "buzz",
// "precededBy": "\n foo bar\n fizz "
// }
// ]
// }
Since common-tags
is built on the foundation of this TemplateTag class, it comes with its own set of built-in transformers:
trimResultTransformer([side])
Trims the whitespace surrounding the end result. Accepts an optional side
(can be "start"
or "end"
or alternatively "left"
or "right"
) that when supplied, will only trim whitespace from that side of the string.
stripIndentTransformer([type='initial'])
Strips the indents from the end result. Offers two types: all
, which removes all indentation from each line, and initial
, which removes the shortest indent level from each line. Defaults to initial
.
replaceResultTransformer(replaceWhat, replaceWith)
Replaces a value or pattern in the end result with a new value. replaceWhat
can be a string or a regular expression, replaceWith
is the new value.
replaceSubstitutionTransformer(replaceWhat, replaceWith)
Replaces the result of all substitutions (results of calling ${ ... }
) with a new value. Same as for replaceResultTransformer
, replaceWhat
can be a string or regular expression and replaceWith
is the new value.
replaceStringTransformer(replaceWhat, replaceWith)
Replaces the result of all strings (what's not in ${ ... }
) with a new value. Same as for replaceResultTransformer
, replaceWhat
can be a string or regular expression and replaceWith
is the new value.
inlineArrayTransformer(opts)
Converts any array substitutions into a string that represents a list. Accepts an options object:
opts = {
separator: ',', // what to separate each item with (always followed by a space)
conjunction: 'and', // replace the last separator with this value
serial: true // should the separator be included before the conjunction? As in the case of serial/oxford commas
}
splitStringTransformer(splitBy)
Splits a string substitution into an array by the provided splitBy
substring, only if the string contains the splitBy
substring.
Please see the Contribution Guidelines.
MIT. See license.md.
If common-tags
doesn't quite fit your bill, and you just can't seem to find what you're looking for - perhaps these might be of use to you?
FAQs
a few common utility template tags for ES2015
The npm package common-tags receives a total of 10,986,156 weekly downloads. As such, common-tags popularity was classified as popular.
We found that common-tags demonstrated a not healthy version release cadence and project activity because the last version was released a year ago.Β It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.