@jodzjcm/string-format
v1.2.0
Published
A string formatter inspired by Angular's text interpolation.
Downloads
22
Maintainers
Readme
@jodzjcm/string-format
This is a string interpolation library inspired by how Angular embeds an expression into a formatted string.
Installation
npm i @jodzjcm/string-format
Require:
import { formatString } from "@jodzjcm/string-format";
Usage
Provide a string literal with one or more placeholders, and a data as its reference to interpolate a formatted string.
formatString( stringTemplate : string, object : Object, opts ? : any );
const greeting = "Hello";
const STR = formatString("{{ :greeting }} world!", { greeting } );
console.log(STR); //OUTPUT: "Hello world!"
const lives = 9;
const STR = formatString("A cat has {{ :lives }} lives.", { lives } );
console.log(STR); //OUTPUT: "A cat has 9 lives."
const DATA = { greetings : "Hello" };
const STR = formatString("{{ :greetings }} world!", DATA);
console.log(STR); //OUTPUT: "Hello world!"
Accessing Object Properties
To access object properties, use the dot notation as shown below.
const CAT_DATA = {
info: {
name : "Tiger"
age: 8,
species: "cat",
type: "tabby",
residence: {
country: "Philippines"
},
hobbies : ["Eating","Sleeping", "Playing"]
}
};
const STR1 = formatString(
"Hi! I'm {{ :info.name }} and I'm a {{ :info.type }} {{ :info.species }} from the {{ :info.residence.country }}.", CAT_DATA);
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and I'm a tabby cat from the Philippines."
const STR1 = formatString(
"Hi! I'm {{ :info.name }} and I'm a {{ :info.type }} {{ :info.species }} from the {{ :info.residence.country }}." , CAT_DATA);
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and I'm a tabby cat from the Philippines."
Accessing Array Elements
Use @<index>
, @<startingIndex>-<endIndex>
, and @<startingIndex>-
to access array elements.
//using CAT_DATA from the previous example.
const STR1 = formatString("Hi! I'm {{ :info.name }} and I like to {{ :info.hobbies.@2 }}.", CAT_DATA);
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and I like Playing."
You can also define ranges to enumerate the elements of an array accordingly into the placeholder. If the end index is not provided, it will take up the length of the provided array.
//using CAT_DATA from the previous example.
const STR1 = formatString(
"Hi! I'm {{ :info.name }} and my hobbies are: {{ :info.hobbies.@0- }}.", CAT_DATA);
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and my hobbies are: Eating Sleeping Playing."
//using CAT_DATA from the previous example.
const STR1 = formatString("Hi! I'm {{ :info.name }} and my hobbies are: {{ :info.hobbies.@1-2 }}.", CAT_DATA);
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and my hobbies are: Sleeping Playing."
const TEST_DATA = {
numbers2: [
[
[0, 1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
],
[
[11, 12, 13, 14, 15],
[16]
],
],
};
//OUTPUT => 6 7 8 9 10 16.
console.log(formatString("{{:numbers2.@0-.@1.@0-}}.", TEST_DATA));
Accessing JSON String
To make things easier, you could access a json string directly by using !
in your expression.
const JSON_CHILD_2 = {
team: "Team 3&5 - GSW",
year: [2014, 2019],
members: ["Steph", "Dray", "Klay", "Durant", true, undefined, false, null], //json.stringify converts `undefined` to `null`
complexChild: [
{ data: JSON.stringify(CAT_DATA) },
{ data: JSON.stringify(CAT_DATA) },
],
};
const JSON_CHILD_1 = {
randomNumber: 70,
child: JSON.stringify(JSON_CHILD_2),
};
const JSON_MAIN = {
name: "Tiger",
age: 30,
city: "New York",
child: JSON.stringify(JSON_CHILD_1),
};
//THE_EXAMPLE.raw is a JSON string.
const THE_EXAMPLE = { myRawJSONString: JSON.stringify(JSON_MAIN) };
Indicate !
to automatically interpret the JSON string and use the existing notations discussed to access its properties.
formatString("Hello {{:!myRawJSONString.name}}.", THE_EXAMPLE); //OUTPUT: Hello Tiger.
formatString("{{:!myRawJSONString.!child.randomNumber}}.", THE_EXAMPLE); //OUTPUT: 70.
formatString("{{:!myRawJSONString.!child.!child.year.@0-}}.", THE_EXAMPLE); //OUTPUT: 2014 2019.
//uses the cat data test data in the previous examples
formatString("{{:[email protected]}} {{:[email protected]}}.", THE_EXAMPLE);
//OUTPUT: Tiger Tiger Tiger Tiger.
For performance considerations, the resulting values when parsing the JSON string are cached ephemerally until the end of the function's invocation.
Pipes
Pipes are used to do transformations of the interpolated string.
//using CAT_DATA from the previous example above.
const STR1 = formatString("Hi! I'm {{ :info.name }} and my hobbies are: {{ :info.hobbies.@1-2 | !toLowerCase }}.", CAT_DATA);
//Sleeping and playing are now in lowercase.
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and my hobbies are: sleeping playing."
A pipe prefixed by !
are built-in javascript string methods as documented here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String.
Take note that you can't pass params to the string methods in our template or placeholders hence it is recommended to use functions that takes no or optional params. If you really need to pass params, you may need to create a custom pipe.
Chaining Pipes
You could also chain pipes using -->
.
//using CAT_DATA from the previous example above.
const STR1 = formatString(
"Hi! I'm {{ :info.name }} and my hobbies are: {{ :info.hobbies.@1-2 | !toLowerCase --> !toUpperCase}}.", CAT_DATA);
//Sleeping and playing are now in lowercase and will be uppercased
console.log(STR1); //OUTPUT: "Hi! I'm Tiger and my hobbies are: SLEEPING PLAYING."
You can chain two or more pipes.
"Hi! I'm {{ :info.name }} and my hobbies are:
{{ :info.hobbies.@1-2 | pipe1 --> pipe2 ---> pipe3 --> andSoOn }}.", CAT_DATA);
Available Pipes
Built-in string methods prefixed by
!
as discussed above. Case sensitive when providing built-in string methods.SQLStringEscape (shorthand: sqlq)
- Escapes or sanitizes the data. The pipe internally calls
SqlString.escape(yourData)
to sanitize the string before placing it to the placehoder. For more info, https://www.npmjs.com/package/sqlstring.
Usage:
formatString("SELECT * FROM Users WHERE surrogateId = {{ :mydata.myattr.id | SQLStringEscape }}", QUERY ); formatString("SELECT * FROM Users WHERE surrogateId = {{ :mydata.myattr.id | sqlq }}", QUERY );
- Escapes or sanitizes the data. The pipe internally calls
toJSON
- parses the data into JSON.
parseJSON
- reads the JSON and dumps its output in the string template.
ReverseString
Creating Custom Pipes
If you want to create your own set of transformation rules like transforming dates using your favorite library like date-fns
or moment
, you may need to create your own pipes.
To create your own transformation pipe, provide the options object which is third param of the formatString
and assign a property named pipes
.
pipes : Array<{
name : string,
action(value : any): string
}
Example:
formatString("{{:msg | aReplacer --> !toLowerCase }}.",
{
msg: "helLo a!",
},{
pipes: [
{
name: "aReplacer",
action: (value: any) => (value + "").replace("a", "wooorld!"),
},
],
});
//The output: "hello wooorld!."