Skip to content

Commit

Permalink
export template function (#8)
Browse files Browse the repository at this point in the history
* Export template function

This facilitates wrapping template behavior in other functions, and not needing to reference the tag function in many places.

* Add tests and types

Additionally add typescript as a dev dependency

* Update README
  • Loading branch information
GeorgeTaveras1231 authored Mar 4, 2022
1 parent bc92e93 commit e5a2993
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 3 deletions.
12 changes: 12 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,15 @@ log(chalk.red.bgBlack(chalkTemplate`2 + 3 = {bold ${2 + 3}}`));
```
*/
export default function chalkTemplate(text: TemplateStringsArray, ...placeholders: unknown[]): string;

/**
Terminal string styling. It is preferred that you use the template tag (default export) but this function is useful if you'd like to wrap the color template function.
@example
```
import { template } from 'chalk-template';
log(template('Today is {red hot}')
```
*/
export function template(text: string): string;
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ function buildStyle(styles) {
return current;
}

function template(string) {
export function template(string) {
const styles = [];
const chunks = [];
let chunk = [];
Expand Down
4 changes: 3 additions & 1 deletion index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {expectType} from 'tsd';
import chalk from 'chalk';
import chalkTemplate from './index.js';
import chalkTemplate, {template} from './index.js';

// -- Template literal --
expectType<string>(chalkTemplate``);
const name = 'John';
expectType<string>(chalkTemplate`Hello {bold.red ${name}}`);
expectType<string>(chalkTemplate`Works with numbers {bold.red ${1}}`);

expectType<string>(template('Today is {bold.red hot}'));

// -- Complex template literal --
expectType<string>(chalk.red.bgGreen.bold(chalkTemplate`Hello {italic.blue ${name}}`));
expectType<string>(chalk.strikethrough.cyanBright.bgBlack(chalkTemplate`Works with {reset {bold numbers}} {bold.red ${1}}`));
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"node": ">=12"
},
"scripts": {
"test": "xo && ava test/index.js && cross-env FORCE_COLOR=0 ava test/no-color.js && cross-env FORCE_COLOR=3 TERM=dumb ava test/full-color.js && tsd"
"test": "xo && ava test/index.js && cross-env FORCE_COLOR=0 ava test/no-color.js && cross-env FORCE_COLOR=3 TERM=dumb ava test/full-color.js && cross-env FORCE_COLOR=3 TERM=dumb ava test/template.js && tsd"
},
"files": [
"index.js",
Expand Down Expand Up @@ -49,6 +49,7 @@
"ava": "^3.15.0",
"cross-env": "^7.0.3",
"tsd": "^0.18.0",
"typescript": "^4.6.2",
"xo": "^0.45.0"
}
}
10 changes: 10 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ Note that function styles (`rgb()`, etc.) may not contain spaces between paramet

All interpolated values (`` chalkTemplate`${foo}` ``) are converted to strings via the `.toString()` method. All curly braces (`{` and `}`) in interpolated value strings are escaped.

## Template function

You may also use the template function as an alternative to the tagged template function.

```js
import {template} from 'chalk-template';

console.log(template('Today is {red hot}'));
```

## Related

- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right
Expand Down
78 changes: 78 additions & 0 deletions test/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import test from 'ava';
import {template} from '../index.js';

test('correctly parse and evaluate color-convert functions', t => {
t.is(template('{bold.rgb(144,10,178).inverse Hello, {~inverse there!}}'),
'\u001B[1m\u001B[38;2;144;10;178m\u001B[7mHello, '
+ '\u001B[27m\u001B[39m\u001B[22m\u001B[1m'
+ '\u001B[38;2;144;10;178mthere!\u001B[39m\u001B[22m');

t.is(template('{bold.bgRgb(144,10,178).inverse Hello, {~inverse there!}}'),
'\u001B[1m\u001B[48;2;144;10;178m\u001B[7mHello, '
+ '\u001B[27m\u001B[49m\u001B[22m\u001B[1m'
+ '\u001B[48;2;144;10;178mthere!\u001B[49m\u001B[22m');
});

test('properly handle escapes', t => {
t.is(template('{bold hello \\{in brackets\\}}'),
'\u001B[1mhello {in brackets}\u001B[22m');
});

test('throw if there is an unclosed block', t => {
t.throws(() => {
template('{bold this shouldn\'t work ever\\}');
}, {
message: 'Chalk template literal is missing 1 closing bracket (`}`)',
});

t.throws(() => {
template('{bold this shouldn\'t {inverse appear {underline ever\\} :) \\}');
}, {
message: 'Chalk template literal is missing 3 closing brackets (`}`)',
});
});

test('throw if there is an invalid style', t => {
t.throws(() => {
template('{abadstylethatdoesntexist this shouldn\'t work ever}');
}, {
message: 'Unknown Chalk style: abadstylethatdoesntexist',
});
});

test('properly style multiline color blocks', t => {
t.is(
template(`{bold
Hello! This is a
${'multiline'} block!
:)
} {underline
I hope you enjoy
}`),
'\u001B[1m\u001B[22m\n'
+ '\u001B[1m\t\t\tHello! This is a\u001B[22m\n'
+ '\u001B[1m\t\t\tmultiline block!\u001B[22m\n'
+ '\u001B[1m\t\t\t:)\u001B[22m\n'
+ '\u001B[1m\t\t\u001B[22m \u001B[4m\u001B[24m\n'
+ '\u001B[4m\t\t\tI hope you enjoy\u001B[24m\n'
+ '\u001B[4m\t\t\u001B[24m',
);
});

test('should allow bracketed Unicode escapes', t => {
t.is(template('\u{AB}'), '\u{AB}');
t.is(template('This is a {bold \u{AB681}} test'), 'This is a \u001B[1m\u{AB681}\u001B[22m test');
t.is(template('This is a {bold \u{10FFFF}} test'), 'This is a \u001B[1m\u{10FFFF}\u001B[22m test');
});

test('should handle special hex case', t => {
t.is(template('{#FF0000 hello}'), '\u001B[38;2;255;0;0mhello\u001B[39m');
t.is(template('{#:FF0000 hello}'), '\u001B[48;2;255;0;0mhello\u001B[49m');
t.is(template('{#00FF00:FF0000 hello}'), '\u001B[38;2;0;255;0m\u001B[48;2;255;0;0mhello\u001B[49m\u001B[39m');
t.is(template('{bold.#FF0000 hello}'), '\u001B[1m\u001B[38;2;255;0;0mhello\u001B[39m\u001B[22m');
t.is(template('{bold.#:FF0000 hello}'), '\u001B[1m\u001B[48;2;255;0;0mhello\u001B[49m\u001B[22m');
t.is(template('{bold.#00FF00:FF0000 hello}'), '\u001B[1m\u001B[38;2;0;255;0m\u001B[48;2;255;0;0mhello\u001B[49m\u001B[39m\u001B[22m');
t.is(template('{#FF0000.bold hello}'), '\u001B[38;2;255;0;0m\u001B[1mhello\u001B[22m\u001B[39m');
t.is(template('{#:FF0000.bold hello}'), '\u001B[48;2;255;0;0m\u001B[1mhello\u001B[22m\u001B[49m');
t.is(template('{#00FF00:FF0000.bold hello}'), '\u001B[38;2;0;255;0m\u001B[48;2;255;0;0m\u001B[1mhello\u001B[22m\u001B[49m\u001B[39m');
});

0 comments on commit e5a2993

Please sign in to comment.