Skip to content

Commit 1fa8c59

Browse files
authored
feat: Add support for LESS asset type (#11)
1 parent 362ec65 commit 1fa8c59

File tree

8 files changed

+199
-1
lines changed

8 files changed

+199
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Options:
5050
-o, --output <value> specify output directory
5151
-n, --name <value> base name of the font set used both as default asset name (default: icons)
5252
-t, --font-types <value...> specify font formats to generate (default: eot, woff2, woff, available: eot, woff2, woff, ttf, svg)
53-
-g --asset-types <value...> specify other asset types to generate (default: css, html, json, ts, available: css, scss, sass, html, json, ts)
53+
-g --asset-types <value...> specify other asset types to generate (default: css, html, json, ts, available: css, less, scss, sass, html, json, ts)
5454
-h, --font-height <value> the output font height (icons will be scaled so the highest has this height) (default: 300)
5555
--descent <value> the font descent
5656
--normalize [bool] normalize icons by scaling them to the height of the highest icon

src/core/__tests__/config-parser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const mockConfig = {
3030
fontsUrl: '/fonts',
3131
templates: {
3232
css: 'css',
33+
less: 'less',
3334
sass: 'sass',
3435
scss: 'scss',
3536
html: 'html'
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`\`LESS\` asset generator renders LESS correctly with \`selector\` option 1`] = `
4+
"@test-font: "test";
5+
6+
@font-face {
7+
font-display: block;
8+
font-family: @test-font;
9+
src: "::src-attr::";
10+
}
11+
12+
.my-selector::before {
13+
font-family: test !important;
14+
font-style: normal;
15+
font-weight: normal !important;
16+
font-variant: normal;
17+
text-transform: none;
18+
line-height: 1;
19+
-webkit-font-smoothing: antialiased;
20+
-moz-osx-font-smoothing: grayscale;
21+
}
22+
23+
@test-map: {
24+
my-icon: "\\f101";
25+
}
26+
27+
.my-selector.tf-my-icon::before {
28+
content: @test-map[my-icon];
29+
}
30+
"
31+
`;
32+
33+
exports[`\`LESS\` asset generator renders LESS correctly with prefix and tag name options 1`] = `
34+
"@test-font: "test";
35+
36+
@font-face {
37+
font-display: block;
38+
font-family: @test-font;
39+
src: "::src-attr::";
40+
}
41+
42+
b[class^="tf-"]::before, b[class*=" tf-"]::before {
43+
font-family: test !important;
44+
font-style: normal;
45+
font-weight: normal !important;
46+
font-variant: normal;
47+
text-transform: none;
48+
line-height: 1;
49+
-webkit-font-smoothing: antialiased;
50+
-moz-osx-font-smoothing: grayscale;
51+
}
52+
53+
@test-map: {
54+
my-icon: "\\f101";
55+
}
56+
57+
.tf-my-icon::before {
58+
content: @test-map[my-icon];
59+
}
60+
"
61+
`;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import lessGen from '../less';
2+
import { renderSrcAttribute } from '../../../utils/css';
3+
import { resolve } from 'path';
4+
5+
const renderSrcMock = renderSrcAttribute as any as jest.Mock;
6+
7+
const mockOptions = {
8+
name: 'test',
9+
prefix: 'tf',
10+
tag: 'b',
11+
codepoints: { 'my-icon': 0xf101 },
12+
assets: { 'my-icon': null },
13+
templates: {
14+
less: resolve(__dirname, '../../../../templates/less.hbs')
15+
}
16+
} as any;
17+
18+
jest.mock('../../../utils/css', () => ({
19+
renderSrcAttribute: jest.fn(() => '"::src-attr::"')
20+
}));
21+
22+
describe('`LESS` asset generator', () => {
23+
beforeEach(() => {
24+
renderSrcMock.mockClear();
25+
});
26+
27+
test('renders LESS correctly with prefix and tag name options', async () => {
28+
expect(
29+
await lessGen.generate(mockOptions, Buffer.from(''))
30+
).toMatchSnapshot();
31+
});
32+
33+
test('renders LESS correctly with `selector` option', async () => {
34+
expect(
35+
await lessGen.generate(
36+
{ ...mockOptions, selector: '.my-selector' },
37+
Buffer.from('')
38+
)
39+
).toMatchSnapshot();
40+
});
41+
42+
test('calls renderSrcAttribute correctly and includes its return value in the rendered template', async () => {
43+
const fontBuffer = Buffer.from('::svg-content::');
44+
45+
const result = await lessGen.generate(mockOptions, fontBuffer);
46+
47+
expect(renderSrcMock).toHaveBeenCalledTimes(1);
48+
expect(renderSrcMock).toHaveBeenCalledWith(mockOptions, fontBuffer);
49+
expect(result).toContain('::src-attr::');
50+
});
51+
52+
test('renders expected selector blocks', async () => {
53+
const less = await lessGen.generate(mockOptions, Buffer.from(''));
54+
55+
expect(less).toContain(
56+
'b[class^="tf-"]::before, b[class*=" tf-"]::before {'
57+
);
58+
expect(less).toContain('.tf-my-icon::before {');
59+
});
60+
61+
test('renders expected variables', async () => {
62+
const less = await lessGen.generate(mockOptions, Buffer.from(''));
63+
64+
expect(less).toContain('@test-font:');
65+
expect(less).toContain('@test-map:');
66+
});
67+
68+
test('renders expected selector blocks with `selector` option', async () => {
69+
const less = await lessGen.generate(
70+
{ ...mockOptions, selector: '.my-selector' },
71+
Buffer.from('')
72+
);
73+
74+
expect(less).toContain('.my-selector::before {');
75+
expect(less).toContain('.my-selector.tf-my-icon::before {');
76+
});
77+
});

src/generators/asset-types/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import css from './css';
99
import html from './html';
1010
import json from './json';
1111
import ts from './ts';
12+
import less from './less';
1213
import sass from './sass';
1314
import scss from './scss';
1415

@@ -22,6 +23,7 @@ const generators: { [key in AssetType]: FontGenerator<any> } = {
2223
[OtherAssetType.HTML]: html,
2324
[OtherAssetType.JSON]: json,
2425
[OtherAssetType.TS]: ts,
26+
[OtherAssetType.LESS]: less,
2527
[OtherAssetType.SASS]: sass,
2628
[OtherAssetType.SCSS]: scss
2729
};

src/generators/asset-types/less.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { FontGenerator } from '../../types/generator';
2+
import { FontAssetType } from '../../types/misc';
3+
import { renderTemplate } from '../../utils/template';
4+
import { renderSrcAttribute } from '../../utils/css';
5+
6+
const generator: FontGenerator<Buffer> = {
7+
dependsOn: FontAssetType.SVG,
8+
9+
generate: (options, svg: Buffer) =>
10+
renderTemplate(
11+
options.templates.less,
12+
{ ...options, fontSrc: renderSrcAttribute(options, svg) },
13+
{ helpers: { codepoint: str => str.toString(16) } }
14+
)
15+
};
16+
17+
export default generator;

src/types/misc.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export enum FontAssetType {
88

99
export enum OtherAssetType {
1010
CSS = 'css',
11+
LESS = 'less',
1112
SCSS = 'scss',
1213
SASS = 'sass',
1314
HTML = 'html',
@@ -18,6 +19,7 @@ export enum OtherAssetType {
1819
export const ASSET_TYPES_WITH_TEMPLATE = [
1920
OtherAssetType.CSS,
2021
OtherAssetType.HTML,
22+
OtherAssetType.LESS,
2123
OtherAssetType.SCSS,
2224
OtherAssetType.SASS
2325
];

templates/less.hbs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@{{ name }}-font: "{{ name }}";
2+
3+
@font-face {
4+
font-display: block;
5+
font-family: @{{ name }}-font;
6+
src: {{{ fontSrc }}};
7+
}
8+
9+
{{# if selector }}
10+
{{ selector }}::before {
11+
{{ else }}
12+
{{ tag }}[class^="{{prefix}}-"]::before, {{ tag }}[class*=" {{prefix}}-"]::before {
13+
{{/ if }}
14+
font-family: {{ name }} !important;
15+
font-style: normal;
16+
font-weight: normal !important;
17+
font-variant: normal;
18+
text-transform: none;
19+
line-height: 1;
20+
-webkit-font-smoothing: antialiased;
21+
-moz-osx-font-smoothing: grayscale;
22+
}
23+
24+
@{{ name }}-map: {
25+
{{# each codepoints }}
26+
{{ @key }}: "\\{{ codepoint this }}";
27+
{{/ each }}
28+
}
29+
30+
{{# each codepoints }}
31+
{{# if ../selector }}
32+
{{ ../selector }}.{{ ../prefix }}-{{ @key }}::before {
33+
{{ else }}
34+
{{ tag }}.{{ ../prefix }}-{{ @key }}::before {
35+
{{/ if }}
36+
content: @{{ ../name }}-map[{{ @key }}];
37+
}
38+
{{/ each }}

0 commit comments

Comments
 (0)