Skip to content

Commit

Permalink
Test and export templateHelpers
Browse files Browse the repository at this point in the history
Usage:

```javascript
import templateHelpers from 'chordsheetjs';

const {
  isChordLyricsPair,
  lineHasContents,
  isTag,
  isComment,
  stripHTML,
  each,
  when,
  hasTextContents,
  lineClasses,
  paragraphClasses,
  evaluate,
  fontStyleTag,
} = templateHelpers;
```

Resolves #934
  • Loading branch information
martijnversluis committed Aug 28, 2023
1 parent b2655fa commit 00763c5
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 18 deletions.
5 changes: 3 additions & 2 deletions src/formatter/templates/html_div_formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { renderChord } from '../../helpers';

import {
each,
evaluate, fontStyleTag,
evaluate,
fontStyleTag,
isChordLyricsPair,
isComment,
isEvaluatable,
isTag, keep,
isTag,
lineClasses,
lineHasContents,
paragraphClasses,
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Tag from './chord_sheet/tag';
import Ternary from './chord_sheet/chord_pro/ternary';
import TextFormatter from './formatter/text_formatter';
import UltimateGuitarParser from './parser/ultimate_guitar_parser';
import * as templateHelpers from './template_helpers';

import {
CHORUS,
Expand Down Expand Up @@ -50,6 +51,7 @@ export { default as Tag } from './chord_sheet/tag';
export { default as Ternary } from './chord_sheet/chord_pro/ternary';
export { default as TextFormatter } from './formatter/text_formatter';
export { default as UltimateGuitarParser } from './parser/ultimate_guitar_parser';
export * as templateHelpers from './template_helpers';

export {
CHORUS,
Expand Down Expand Up @@ -87,4 +89,5 @@ export default {
NONE,
TAB,
VERSE,
templateHelpers,
};
18 changes: 3 additions & 15 deletions src/template_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ interface WhenCallback {
(): string;
}

interface KeepCallback {
(_items: any[]): string;
}

export { isEvaluatable } from './utilities';

export const isChordLyricsPair = (item: Item): boolean => item instanceof ChordLyricsPair;
Expand All @@ -44,10 +40,6 @@ export function when(condition: any, callback: WhenCallback): string {
return condition ? callback() : '';
}

export function keep(variables: any[], callback: KeepCallback): string {
return callback.call(null, variables);
}

export const hasTextContents = (line: Line): boolean => (
line.items.some((item) => (
(item instanceof ChordLyricsPair && !isEmptyString(item.lyrics))
Expand Down Expand Up @@ -76,13 +68,9 @@ export const paragraphClasses = (paragraph: Paragraph): string => {
return classes.join(' ');
};

export const evaluate = (item: Evaluatable, metadata: Metadata, configuration: Configuration): string => {
if (!metadata) {
throw new Error('cannot evaluate, metadata is null');
}

return item.evaluate(metadata, configuration.get('metadata.separator'));
};
export const evaluate = (item: Evaluatable, metadata: Metadata, configuration: Configuration): string => (
item.evaluate(metadata, configuration.get('metadata.separator'))
);

export function fontStyleTag(font: Font) {
const cssString = font.toCssString();
Expand Down
1 change: 1 addition & 0 deletions test/default_export.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('default export', () => {
'INDETERMINATE',
'VERSE',
'NONE',
'templateHelpers',
].forEach((constantName) => {
it(`contains ${constantName}`, () => {
expect(typeof chordsheetjs[constantName]).not.toEqual('undefined');
Expand Down
3 changes: 2 additions & 1 deletion test/parser/chord_pro_parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
CHORUS,
NONE,
VERSE,
TAB, Ternary,
TAB,
Ternary,
} from '../../src';

import '../matchers';
Expand Down
283 changes: 283 additions & 0 deletions test/template_helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
import {
CHORUS,
ChordLyricsPair,
Comment,
Line,
Metadata,
NONE,
Paragraph,
Tag,
Ternary,
templateHelpers,
} from '../src';

import Configuration from '../src/formatter/configuration/configuration';
import Font from '../src/chord_sheet/font';
import FontSize from '../src/chord_sheet/font_size';

const {
isChordLyricsPair,
lineHasContents,
isTag,
isComment,
stripHTML,
each,
when,
hasTextContents,
lineClasses,
paragraphClasses,
evaluate,
fontStyleTag,
} = templateHelpers;

describe('template_helpers', () => {
describe('isChordLyricsPair', () => {
it('returns true when the item is a ChordLyricsPair', () => {
expect(isChordLyricsPair(new ChordLyricsPair())).toBe(true);
});

it('returns false for all other items', () => {
expect(isChordLyricsPair(new Comment('test comment'))).toBe(false);
expect(isChordLyricsPair(new Tag('test'))).toBe(false);
expect(isChordLyricsPair(new Ternary({}))).toBe(false);
});
});

describe('lineHasContents', () => {
it('returns true when the line has renderable items', () => {
const line = new Line({
type: NONE,
items: [new ChordLyricsPair('A', 'hello')],
});

expect(lineHasContents(line)).toBe(true);
});

it('returns false when the line has no renderable items', () => {
const line = new Line({
type: NONE,
items: [new Comment('hello')],
});

expect(lineHasContents(line)).toBe(false);
});

it('returns false when the line has no items', () => {
const line = new Line({ type: NONE, items: [] });

expect(lineHasContents(line)).toBe(false);
});
});

describe('isTag', () => {
it('returns true when the item is a ChordLyricsPair', () => {
expect(isTag(new Tag('test'))).toBe(true);
});

it('returns false when the item is not a ChordLyricsPair', () => {
expect(isTag(new ChordLyricsPair())).toBe(false);
expect(isTag(new Comment('test comment'))).toBe(false);
expect(isTag(new Ternary({}))).toBe(false);
});
});

describe('isComment', () => {
it('returns true when a tag is a comment', () => {
expect(isComment(new Tag('comment', 'hello'))).toBe(true);
expect(isComment(new Tag('c', 'hello'))).toBe(true);
});

it('returns false when a tag is not a comment', () => {
expect(isComment(new Tag('start_of_chorus', 'hello'))).toBe(false);
expect(isComment(new Tag('soc', 'hello'))).toBe(false);
});
});

describe('stripHTML', () => {
it('removes all whitespace from a HTML string', () => {
const expandedHTML = `
<span
class="foo"
> FOO </span>
`;

const strippedHTML = '<span class="foo"> FOO </span>';

expect(stripHTML(expandedHTML)).toEqual(strippedHTML);
});
});

describe('each', () => {
it('invokes the callback which each item and returns a concatenated string', () => {
const callback = (str: string) => str.toUpperCase();
const items = ['foo', 'bar', 'barber', 'barbarian'];
const expectedResult = 'FOOBARBARBERBARBARIAN';

expect(each(items, callback)).toEqual(expectedResult);
});
});

describe('when', () => {
it('returns the callback result when the condition is truthy', () => {
const callback = () => 'foobar!';

expect(when(true, callback)).toEqual('foobar!');
expect(when('string', callback)).toEqual('foobar!');
expect(when({}, callback)).toEqual('foobar!');
expect(when(25, callback)).toEqual('foobar!');
expect(when([], callback)).toEqual('foobar!');
});

it('returns an empty string when the condition is falsy', () => {
const callback = () => 'foobar!';

expect(when(false, callback)).toEqual('');
expect(when(null, callback)).toEqual('');
expect(when(undefined, callback)).toEqual('');
expect(when('', callback)).toEqual('');
expect(when(0, callback)).toEqual('');
});
});

describe('hasTextContents', () => {
it('returns true when an item is a ChordLyricsPair with lyrics', () => {
const line = new Line({
type: NONE,
items: [
new ChordLyricsPair('G', 'hello'),
],
});

expect(hasTextContents(line)).toBe(true);
});

it('returns true when an item is a renderable Tag', () => {
const line = new Line({
type: NONE,
items: [
new Tag('comment', 'hello'),
],
});

expect(hasTextContents(line)).toBe(true);
});

it('returns true when an item is evaluatable', () => {
const line = new Line({
type: NONE,
items: [
new Ternary({ }),
],
});

expect(hasTextContents(line)).toBe(true);
});

it('returns false when an item is an unrenderable Tag', () => {
const line = new Line({
type: NONE,
items: [
new Tag('start_of_chorus', ''),
],
});

expect(hasTextContents(line)).toBe(false);
});

it('returns false when an item is a ChordLyricsPair without lyrics', () => {
const line = new Line({
type: NONE,
items: [
new ChordLyricsPair('G', ''),
],
});

expect(hasTextContents(line)).toBe(false);
});

it('returns false when an item is not evaluatable', () => {
const line = new Line({
type: NONE,
items: [
new Comment('test'),
],
});

expect(hasTextContents(line)).toBe(false);
});

it('returns false when the line does not have any items', () => {
const line = new Line({ type: NONE, items: [] });

expect(hasTextContents(line)).toBe(false);
});
});

describe('lineClasses', () => {
it('returns [row empty-line] when the line has no contents', () => {
const line = new Line({
type: NONE,
items: [],
});

expect(lineClasses(line)).toEqual('row empty-line');
});

it('returns [row] when the line has contents', () => {
const line = new Line({
type: NONE,
items: [new ChordLyricsPair('A', 'hello')],
});

expect(lineClasses(line)).toEqual('row');
});
});

describe('paragraphClasses', () => {
it('returns [paragraph <paragraph type>] when the paragraph has a type', () => {
const line = new Line({ type: CHORUS, items: [] });
const paragraph = new Paragraph();
paragraph.addLine(line);

expect(paragraphClasses(paragraph)).toEqual('paragraph chorus');
});

it('returns [paragraph] when the paragraph type is NONE', () => {
const line = new Line({ type: NONE, items: [] });
const paragraph = new Paragraph();
paragraph.addLine(line);

expect(paragraphClasses(paragraph)).toEqual('paragraph');
});

it('returns [paragraph] when the paragraph type is INDETERMINATE', () => {
const paragraph = new Paragraph();

expect(paragraphClasses(paragraph)).toEqual('paragraph');
});
});

describe('evaluate', () => {
it('evaluates the item', () => {
const item = new Ternary({ variable: 'composer' });
const metadata = new Metadata({ composer: ['John', 'Mary'] });
const configuration = new Configuration({ metadata: { separator: ' and ' } });

expect(evaluate(item, metadata, configuration)).toEqual('John and Mary');
});
});

describe('fontStyleTag', () => {
it('returns a style tag for a font with properties', () => {
const font = new Font({ font: 'Arial', size: new FontSize(15, 'px'), colour: 'black' });

expect(fontStyleTag(font)).toEqual(' style="color: black; font: 15px Arial"');
});

it('returns an empty string for a font without properties', () => {
const font = new Font();

expect(fontStyleTag(font)).toEqual('');
});
});
});

0 comments on commit 00763c5

Please sign in to comment.