fontaine 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,10 +48,13 @@ yarn add -D fontaine
48
48
  ```js
49
49
  import { FontaineTransform } from 'fontaine'
50
50
 
51
+ // Astro config - astro.config.mjs
52
+ import { defineConfig } from 'astro/config'
53
+
51
54
  const options = {
52
55
  fallbacks: ['BlinkMacSystemFont', 'Segoe UI', 'Helvetica Neue', 'Arial', 'Noto Sans'],
53
56
  // You may need to resolve assets like `/fonts/Roboto.woff2` to a particular directory
54
- resolvePath: (id) => 'file:///path/to/public/dir' + id,
57
+ resolvePath: id => `file:///path/to/public/dir${id}`,
55
58
  // overrideName: (originalName) => `${name} override`
56
59
  // sourcemap: false
57
60
  // skipFontFaceGeneration: (fallbackName) => fallbackName === 'Roboto override'
@@ -83,9 +86,9 @@ function fontainePlugin(_context, _options) {
83
86
  plugins: [
84
87
  fontaine.FontaineTransform.webpack(options),
85
88
  ],
86
- };
89
+ }
87
90
  },
88
- };
91
+ }
89
92
  }
90
93
 
91
94
  // Gatsby config - gatsby-node.js
@@ -97,17 +100,13 @@ exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
97
100
  actions.replaceWebpackConfig(config)
98
101
  }
99
102
 
100
- // Astro config - astro.config.mjs
101
- import { defineConfig } from 'astro/config'
102
- import { FontaineTransform } from 'fontaine'
103
-
104
103
  export default defineConfig({
105
104
  integrations: [],
106
105
  vite: {
107
106
  plugins: [
108
107
  FontaineTransform.vite({
109
108
  fallbacks: ['Arial'],
110
- resolvePath: (id) => new URL(`./public${id}`, import.meta.url), // id is the font src value in the CSS
109
+ resolvePath: id => new URL(`./public${id}`, import.meta.url), // id is the font src value in the CSS
111
110
  }),
112
111
  ],
113
112
  },
package/dist/index.cjs CHANGED
@@ -3,16 +3,39 @@
3
3
  const unplugin = require('unplugin');
4
4
  const magicRegexp = require('magic-regexp');
5
5
  const MagicString = require('magic-string');
6
+ const ufo = require('ufo');
7
+ const pathe = require('pathe');
6
8
  const node_url = require('node:url');
7
9
  const unpack = require('@capsizecss/unpack');
8
10
  const metrics = require('@capsizecss/metrics');
9
- const ufo = require('ufo');
10
- const pathe = require('pathe');
11
11
 
12
12
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
13
13
 
14
14
  const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
15
15
 
16
+ function toPercentage(value, fractionDigits = 4) {
17
+ const percentage = value * 100;
18
+ return `${+percentage.toFixed(fractionDigits)}%`;
19
+ }
20
+ function toCSS(properties, indent = 2) {
21
+ return Object.entries(properties).map(([key, value]) => `${" ".repeat(indent)}${key}: ${value};`).join("\n");
22
+ }
23
+ const QUOTES_RE = magicRegexp.createRegExp(
24
+ magicRegexp.charIn(`"'`).at.lineStart().or(magicRegexp.charIn(`"'`).at.lineEnd()),
25
+ ["g"]
26
+ );
27
+ const FAMILY_RE = magicRegexp.createRegExp(
28
+ magicRegexp.exactly("font-family:").and(magicRegexp.whitespace.optionally()).and(magicRegexp.charNotIn(";}").times.any().as("fontFamily"))
29
+ );
30
+ const SOURCE_RE = magicRegexp.createRegExp(
31
+ magicRegexp.exactly("src:").and(magicRegexp.whitespace.optionally()).and(magicRegexp.charNotIn(";}").times.any().as("src")),
32
+ ["g"]
33
+ );
34
+ const URL_RE = magicRegexp.createRegExp(
35
+ magicRegexp.exactly("url(").and(magicRegexp.charNotIn(")").times.any().as("url")).and(")"),
36
+ ["g"]
37
+ );
38
+ const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
16
39
  function* parseFontFace(css) {
17
40
  const fontFamily = css.match(FAMILY_RE)?.groups.fontFamily;
18
41
  const family = withoutQuotes(fontFamily?.split(",")[0] || "");
@@ -21,20 +44,18 @@ function* parseFontFace(css) {
21
44
  for (const entry of sources || []) {
22
45
  for (const url of entry.matchAll(URL_RE)) {
23
46
  const source = withoutQuotes(url.groups?.url || "");
24
- if (source) {
47
+ if (source)
25
48
  yield { family, source };
26
- }
27
49
  }
28
50
  }
29
51
  }
30
52
  yield { family: "", source: "" };
31
53
  }
32
- const generateFallbackName = (name) => {
54
+ function generateFallbackName(name) {
33
55
  const firstFamily = withoutQuotes(name.split(",").shift());
34
56
  return `${firstFamily} fallback`;
35
- };
36
- const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
37
- const generateFontFace = (metrics, fallback) => {
57
+ }
58
+ function generateFontFace(metrics, fallback) {
38
59
  const {
39
60
  name: fallbackName,
40
61
  font: fallbackFontName,
@@ -50,7 +71,7 @@ const generateFontFace = (metrics, fallback) => {
50
71
  const lineGapOverride = metrics.lineGap / adjustedEmSquare;
51
72
  const declaration = {
52
73
  "font-family": JSON.stringify(fallbackName),
53
- src: `local(${JSON.stringify(fallbackFontName)})`,
74
+ "src": `local(${JSON.stringify(fallbackFontName)})`,
54
75
  "size-adjust": toPercentage(sizeAdjust),
55
76
  "ascent-override": toPercentage(ascentOverride),
56
77
  "descent-override": toPercentage(descentOverride),
@@ -61,49 +82,31 @@ const generateFontFace = (metrics, fallback) => {
61
82
  ${toCSS(declaration)}
62
83
  }
63
84
  `;
64
- };
65
- const toPercentage = (value, fractionDigits = 4) => {
66
- const percentage = value * 100;
67
- return +percentage.toFixed(fractionDigits) + "%";
68
- };
69
- const toCSS = (properties, indent = 2) => Object.entries(properties).map(([key, value]) => " ".repeat(indent) + `${key}: ${value};`).join("\n");
70
- const QUOTES_RE = magicRegexp.createRegExp(
71
- magicRegexp.charIn(`"'`).at.lineStart().or(magicRegexp.charIn(`"'`).at.lineEnd()),
72
- ["g"]
73
- );
74
- const FAMILY_RE = magicRegexp.createRegExp(
75
- magicRegexp.exactly("font-family:").and(magicRegexp.whitespace.optionally()).and(magicRegexp.charNotIn(";}").times.any().as("fontFamily"))
76
- );
77
- const SOURCE_RE = magicRegexp.createRegExp(
78
- magicRegexp.exactly("src:").and(magicRegexp.whitespace.optionally()).and(magicRegexp.charNotIn(";}").times.any().as("src")),
79
- ["g"]
80
- );
81
- const URL_RE = magicRegexp.createRegExp(
82
- magicRegexp.exactly("url(").and(magicRegexp.charNotIn(")").times.any().as("url")).and(")"),
83
- ["g"]
84
- );
85
+ }
85
86
 
86
87
  const metricCache = {};
87
- const filterRequiredMetrics = ({
88
+ function filterRequiredMetrics({
88
89
  ascent,
89
90
  descent,
90
91
  lineGap,
91
92
  unitsPerEm,
92
93
  xWidthAvg
93
- }) => ({
94
- ascent,
95
- descent,
96
- lineGap,
97
- unitsPerEm,
98
- xWidthAvg
99
- });
94
+ }) {
95
+ return {
96
+ ascent,
97
+ descent,
98
+ lineGap,
99
+ unitsPerEm,
100
+ xWidthAvg
101
+ };
102
+ }
100
103
  async function getMetricsForFamily(family) {
101
104
  family = withoutQuotes(family);
102
105
  if (family in metricCache)
103
106
  return metricCache[family];
104
107
  try {
105
108
  const name = metrics.fontFamilyToCamelCase(family);
106
- const { entireMetricsCollection } = await import('@capsizecss/metrics/entireMetricsCollection/dist/capsizecss-metrics-entireMetricsCollection.cjs.js');
109
+ const { entireMetricsCollection } = await import('@capsizecss/metrics/entireMetricsCollection');
107
110
  const metrics$1 = entireMetricsCollection[name];
108
111
  const filteredMetrics = filterRequiredMetrics(metrics$1);
109
112
  metricCache[family] = filteredMetrics;
@@ -115,9 +118,8 @@ async function getMetricsForFamily(family) {
115
118
  }
116
119
  async function readMetrics(_source) {
117
120
  const source = typeof _source !== "string" && "href" in _source ? _source.href : _source;
118
- if (source in metricCache) {
121
+ if (source in metricCache)
119
122
  return Promise.resolve(metricCache[source]);
120
- }
121
123
  const { protocol } = ufo.parseURL(source);
122
124
  if (!protocol)
123
125
  return null;
@@ -128,6 +130,17 @@ async function readMetrics(_source) {
128
130
  }
129
131
 
130
132
  const supportedExtensions = ["woff2", "woff", "ttf"];
133
+ const FONT_FACE_RE = magicRegexp.createRegExp(
134
+ magicRegexp.exactly("@font-face").and(magicRegexp.whitespace.times.any()).and("{").and(magicRegexp.charNotIn("}").times.any()).and("}"),
135
+ ["g"]
136
+ );
137
+ const FONT_FAMILY_RE = magicRegexp.createRegExp(
138
+ magicRegexp.charNotIn(";}").times.any().as("family").after(magicRegexp.exactly("font-family:").and(magicRegexp.whitespace.times.any())).before(magicRegexp.charIn(";}").or(magicRegexp.exactly("").at.lineEnd())),
139
+ ["g"]
140
+ );
141
+ const CSS_RE = magicRegexp.createRegExp(
142
+ magicRegexp.exactly(".").and(magicRegexp.anyOf("sass", "css", "scss")).at.lineEnd()
143
+ );
131
144
  const FontaineTransform = unplugin.createUnplugin(
132
145
  (options) => {
133
146
  const cssContext = options.css = options.css || {};
@@ -162,15 +175,13 @@ const FontaineTransform = unplugin.createUnplugin(
162
175
  if (skipFontFaceGeneration(fallbackName(family)))
163
176
  continue;
164
177
  const metrics = await getMetricsForFamily(family) || source && await readMetricsFromId(source, id).catch(() => null);
165
- if (!metrics) {
178
+ if (!metrics)
166
179
  continue;
167
- }
168
180
  for (let i = options.fallbacks.length - 1; i >= 0; i--) {
169
181
  const fallback = options.fallbacks[i];
170
182
  const fallbackMetrics = await getMetricsForFamily(fallback);
171
- if (!fallbackMetrics) {
183
+ if (!fallbackMetrics)
172
184
  continue;
173
- }
174
185
  const fontFace = generateFontFace(metrics, {
175
186
  name: fallbackName(family),
176
187
  font: fallback,
@@ -193,11 +204,11 @@ const FontaineTransform = unplugin.createUnplugin(
193
204
  s.overwrite(
194
205
  index,
195
206
  index + matchContent.length,
196
- " " + [
207
+ ` ${[
197
208
  families[0],
198
209
  `"${generateFallbackName(families[0])}"`,
199
210
  ...families.slice(1)
200
- ].join(", ")
211
+ ].join(", ")}`
201
212
  );
202
213
  }
203
214
  if (s.hasChanged()) {
@@ -210,17 +221,6 @@ const FontaineTransform = unplugin.createUnplugin(
210
221
  };
211
222
  }
212
223
  );
213
- const FONT_FACE_RE = magicRegexp.createRegExp(
214
- magicRegexp.exactly("@font-face").and(magicRegexp.whitespace.times.any()).and("{").and(magicRegexp.charNotIn("}").times.any()).and("}"),
215
- ["g"]
216
- );
217
- const FONT_FAMILY_RE = magicRegexp.createRegExp(
218
- magicRegexp.charNotIn(";}").times.any().as("family").after(magicRegexp.exactly("font-family:").and(magicRegexp.whitespace.times.any())).before(magicRegexp.charIn(";}").or(magicRegexp.exactly("").at.lineEnd())),
219
- ["g"]
220
- );
221
- const CSS_RE = magicRegexp.createRegExp(
222
- magicRegexp.exactly(".").and(magicRegexp.anyOf("sass", "css", "scss")).at.lineEnd()
223
- );
224
224
 
225
225
  exports.FontaineTransform = FontaineTransform;
226
226
  exports.generateFallbackName = generateFallbackName;
@@ -0,0 +1,32 @@
1
+ import * as unplugin from 'unplugin';
2
+ import { Font } from '@capsizecss/unpack';
3
+
4
+ interface FontaineTransformOptions {
5
+ css?: {
6
+ value?: string;
7
+ };
8
+ fallbacks: string[];
9
+ resolvePath?: (path: string) => string | URL;
10
+ skipFontFaceGeneration?: (fallbackName: string) => boolean;
11
+ /** this should produce an unquoted font family name */
12
+ fallbackName?: (name: string) => string;
13
+ /** @deprecated use fallbackName */
14
+ overrideName?: (name: string) => string;
15
+ sourcemap?: boolean;
16
+ }
17
+ declare const FontaineTransform: unplugin.UnpluginInstance<FontaineTransformOptions, boolean>;
18
+
19
+ declare function generateFallbackName(name: string): string;
20
+ interface FallbackOptions {
21
+ name: string;
22
+ font: string;
23
+ metrics?: FontFaceMetrics;
24
+ [key: string]: any;
25
+ }
26
+ type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
27
+ declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
28
+
29
+ declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
30
+ declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
31
+
32
+ export { FontaineTransform, type FontaineTransformOptions, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics };
@@ -0,0 +1,32 @@
1
+ import * as unplugin from 'unplugin';
2
+ import { Font } from '@capsizecss/unpack';
3
+
4
+ interface FontaineTransformOptions {
5
+ css?: {
6
+ value?: string;
7
+ };
8
+ fallbacks: string[];
9
+ resolvePath?: (path: string) => string | URL;
10
+ skipFontFaceGeneration?: (fallbackName: string) => boolean;
11
+ /** this should produce an unquoted font family name */
12
+ fallbackName?: (name: string) => string;
13
+ /** @deprecated use fallbackName */
14
+ overrideName?: (name: string) => string;
15
+ sourcemap?: boolean;
16
+ }
17
+ declare const FontaineTransform: unplugin.UnpluginInstance<FontaineTransformOptions, boolean>;
18
+
19
+ declare function generateFallbackName(name: string): string;
20
+ interface FallbackOptions {
21
+ name: string;
22
+ font: string;
23
+ metrics?: FontFaceMetrics;
24
+ [key: string]: any;
25
+ }
26
+ type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
27
+ declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
28
+
29
+ declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
30
+ declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
31
+
32
+ export { FontaineTransform, type FontaineTransformOptions, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics };
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ interface FontaineTransformOptions {
16
16
  }
17
17
  declare const FontaineTransform: unplugin.UnpluginInstance<FontaineTransformOptions, boolean>;
18
18
 
19
- declare const generateFallbackName: (name: string) => string;
19
+ declare function generateFallbackName(name: string): string;
20
20
  interface FallbackOptions {
21
21
  name: string;
22
22
  font: string;
@@ -24,9 +24,9 @@ interface FallbackOptions {
24
24
  [key: string]: any;
25
25
  }
26
26
  type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
27
- declare const generateFontFace: (metrics: FontFaceMetrics, fallback: FallbackOptions) => string;
27
+ declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
28
28
 
29
29
  declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
30
30
  declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
31
31
 
32
- export { FontaineTransform, FontaineTransformOptions, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics };
32
+ export { FontaineTransform, type FontaineTransformOptions, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics };
package/dist/index.mjs CHANGED
@@ -1,12 +1,35 @@
1
1
  import { createUnplugin } from 'unplugin';
2
2
  import { createRegExp, charIn, exactly, whitespace, charNotIn, anyOf } from 'magic-regexp';
3
3
  import MagicString from 'magic-string';
4
+ import { parseURL } from 'ufo';
5
+ import { isAbsolute, join } from 'pathe';
4
6
  import { fileURLToPath } from 'node:url';
5
7
  import { fromFile, fromUrl } from '@capsizecss/unpack';
6
8
  import { fontFamilyToCamelCase } from '@capsizecss/metrics';
7
- import { parseURL } from 'ufo';
8
- import { isAbsolute, join } from 'pathe';
9
9
 
10
+ function toPercentage(value, fractionDigits = 4) {
11
+ const percentage = value * 100;
12
+ return `${+percentage.toFixed(fractionDigits)}%`;
13
+ }
14
+ function toCSS(properties, indent = 2) {
15
+ return Object.entries(properties).map(([key, value]) => `${" ".repeat(indent)}${key}: ${value};`).join("\n");
16
+ }
17
+ const QUOTES_RE = createRegExp(
18
+ charIn(`"'`).at.lineStart().or(charIn(`"'`).at.lineEnd()),
19
+ ["g"]
20
+ );
21
+ const FAMILY_RE = createRegExp(
22
+ exactly("font-family:").and(whitespace.optionally()).and(charNotIn(";}").times.any().as("fontFamily"))
23
+ );
24
+ const SOURCE_RE = createRegExp(
25
+ exactly("src:").and(whitespace.optionally()).and(charNotIn(";}").times.any().as("src")),
26
+ ["g"]
27
+ );
28
+ const URL_RE = createRegExp(
29
+ exactly("url(").and(charNotIn(")").times.any().as("url")).and(")"),
30
+ ["g"]
31
+ );
32
+ const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
10
33
  function* parseFontFace(css) {
11
34
  const fontFamily = css.match(FAMILY_RE)?.groups.fontFamily;
12
35
  const family = withoutQuotes(fontFamily?.split(",")[0] || "");
@@ -15,20 +38,18 @@ function* parseFontFace(css) {
15
38
  for (const entry of sources || []) {
16
39
  for (const url of entry.matchAll(URL_RE)) {
17
40
  const source = withoutQuotes(url.groups?.url || "");
18
- if (source) {
41
+ if (source)
19
42
  yield { family, source };
20
- }
21
43
  }
22
44
  }
23
45
  }
24
46
  yield { family: "", source: "" };
25
47
  }
26
- const generateFallbackName = (name) => {
48
+ function generateFallbackName(name) {
27
49
  const firstFamily = withoutQuotes(name.split(",").shift());
28
50
  return `${firstFamily} fallback`;
29
- };
30
- const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
31
- const generateFontFace = (metrics, fallback) => {
51
+ }
52
+ function generateFontFace(metrics, fallback) {
32
53
  const {
33
54
  name: fallbackName,
34
55
  font: fallbackFontName,
@@ -44,7 +65,7 @@ const generateFontFace = (metrics, fallback) => {
44
65
  const lineGapOverride = metrics.lineGap / adjustedEmSquare;
45
66
  const declaration = {
46
67
  "font-family": JSON.stringify(fallbackName),
47
- src: `local(${JSON.stringify(fallbackFontName)})`,
68
+ "src": `local(${JSON.stringify(fallbackFontName)})`,
48
69
  "size-adjust": toPercentage(sizeAdjust),
49
70
  "ascent-override": toPercentage(ascentOverride),
50
71
  "descent-override": toPercentage(descentOverride),
@@ -55,49 +76,31 @@ const generateFontFace = (metrics, fallback) => {
55
76
  ${toCSS(declaration)}
56
77
  }
57
78
  `;
58
- };
59
- const toPercentage = (value, fractionDigits = 4) => {
60
- const percentage = value * 100;
61
- return +percentage.toFixed(fractionDigits) + "%";
62
- };
63
- const toCSS = (properties, indent = 2) => Object.entries(properties).map(([key, value]) => " ".repeat(indent) + `${key}: ${value};`).join("\n");
64
- const QUOTES_RE = createRegExp(
65
- charIn(`"'`).at.lineStart().or(charIn(`"'`).at.lineEnd()),
66
- ["g"]
67
- );
68
- const FAMILY_RE = createRegExp(
69
- exactly("font-family:").and(whitespace.optionally()).and(charNotIn(";}").times.any().as("fontFamily"))
70
- );
71
- const SOURCE_RE = createRegExp(
72
- exactly("src:").and(whitespace.optionally()).and(charNotIn(";}").times.any().as("src")),
73
- ["g"]
74
- );
75
- const URL_RE = createRegExp(
76
- exactly("url(").and(charNotIn(")").times.any().as("url")).and(")"),
77
- ["g"]
78
- );
79
+ }
79
80
 
80
81
  const metricCache = {};
81
- const filterRequiredMetrics = ({
82
+ function filterRequiredMetrics({
82
83
  ascent,
83
84
  descent,
84
85
  lineGap,
85
86
  unitsPerEm,
86
87
  xWidthAvg
87
- }) => ({
88
- ascent,
89
- descent,
90
- lineGap,
91
- unitsPerEm,
92
- xWidthAvg
93
- });
88
+ }) {
89
+ return {
90
+ ascent,
91
+ descent,
92
+ lineGap,
93
+ unitsPerEm,
94
+ xWidthAvg
95
+ };
96
+ }
94
97
  async function getMetricsForFamily(family) {
95
98
  family = withoutQuotes(family);
96
99
  if (family in metricCache)
97
100
  return metricCache[family];
98
101
  try {
99
102
  const name = fontFamilyToCamelCase(family);
100
- const { entireMetricsCollection } = await import('@capsizecss/metrics/entireMetricsCollection/dist/capsizecss-metrics-entireMetricsCollection.cjs.js');
103
+ const { entireMetricsCollection } = await import('@capsizecss/metrics/entireMetricsCollection');
101
104
  const metrics = entireMetricsCollection[name];
102
105
  const filteredMetrics = filterRequiredMetrics(metrics);
103
106
  metricCache[family] = filteredMetrics;
@@ -109,9 +112,8 @@ async function getMetricsForFamily(family) {
109
112
  }
110
113
  async function readMetrics(_source) {
111
114
  const source = typeof _source !== "string" && "href" in _source ? _source.href : _source;
112
- if (source in metricCache) {
115
+ if (source in metricCache)
113
116
  return Promise.resolve(metricCache[source]);
114
- }
115
117
  const { protocol } = parseURL(source);
116
118
  if (!protocol)
117
119
  return null;
@@ -122,6 +124,17 @@ async function readMetrics(_source) {
122
124
  }
123
125
 
124
126
  const supportedExtensions = ["woff2", "woff", "ttf"];
127
+ const FONT_FACE_RE = createRegExp(
128
+ exactly("@font-face").and(whitespace.times.any()).and("{").and(charNotIn("}").times.any()).and("}"),
129
+ ["g"]
130
+ );
131
+ const FONT_FAMILY_RE = createRegExp(
132
+ charNotIn(";}").times.any().as("family").after(exactly("font-family:").and(whitespace.times.any())).before(charIn(";}").or(exactly("").at.lineEnd())),
133
+ ["g"]
134
+ );
135
+ const CSS_RE = createRegExp(
136
+ exactly(".").and(anyOf("sass", "css", "scss")).at.lineEnd()
137
+ );
125
138
  const FontaineTransform = createUnplugin(
126
139
  (options) => {
127
140
  const cssContext = options.css = options.css || {};
@@ -156,15 +169,13 @@ const FontaineTransform = createUnplugin(
156
169
  if (skipFontFaceGeneration(fallbackName(family)))
157
170
  continue;
158
171
  const metrics = await getMetricsForFamily(family) || source && await readMetricsFromId(source, id).catch(() => null);
159
- if (!metrics) {
172
+ if (!metrics)
160
173
  continue;
161
- }
162
174
  for (let i = options.fallbacks.length - 1; i >= 0; i--) {
163
175
  const fallback = options.fallbacks[i];
164
176
  const fallbackMetrics = await getMetricsForFamily(fallback);
165
- if (!fallbackMetrics) {
177
+ if (!fallbackMetrics)
166
178
  continue;
167
- }
168
179
  const fontFace = generateFontFace(metrics, {
169
180
  name: fallbackName(family),
170
181
  font: fallback,
@@ -187,11 +198,11 @@ const FontaineTransform = createUnplugin(
187
198
  s.overwrite(
188
199
  index,
189
200
  index + matchContent.length,
190
- " " + [
201
+ ` ${[
191
202
  families[0],
192
203
  `"${generateFallbackName(families[0])}"`,
193
204
  ...families.slice(1)
194
- ].join(", ")
205
+ ].join(", ")}`
195
206
  );
196
207
  }
197
208
  if (s.hasChanged()) {
@@ -204,16 +215,5 @@ const FontaineTransform = createUnplugin(
204
215
  };
205
216
  }
206
217
  );
207
- const FONT_FACE_RE = createRegExp(
208
- exactly("@font-face").and(whitespace.times.any()).and("{").and(charNotIn("}").times.any()).and("}"),
209
- ["g"]
210
- );
211
- const FONT_FAMILY_RE = createRegExp(
212
- charNotIn(";}").times.any().as("family").after(exactly("font-family:").and(whitespace.times.any())).before(charIn(";}").or(exactly("").at.lineEnd())),
213
- ["g"]
214
- );
215
- const CSS_RE = createRegExp(
216
- exactly(".").and(anyOf("sass", "css", "scss")).at.lineEnd()
217
- );
218
218
 
219
219
  export { FontaineTransform, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics };
package/package.json CHANGED
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "name": "fontaine",
3
- "version": "0.4.0",
3
+ "type": "module",
4
+ "version": "0.5.0",
5
+ "packageManager": "pnpm@8.15.4",
4
6
  "description": "Automatic font fallback based on font metrics",
7
+ "author": {
8
+ "name": "Daniel Roe <daniel@roe.dev>",
9
+ "url": "https://github.com/danielroe"
10
+ },
11
+ "license": "MIT",
5
12
  "repository": "unjs/fontaine",
6
13
  "keywords": [
7
14
  "fonts",
@@ -9,13 +16,7 @@
9
16
  "web-vitals",
10
17
  "performance"
11
18
  ],
12
- "author": {
13
- "name": "Daniel Roe <daniel@roe.dev>",
14
- "url": "https://github.com/danielroe"
15
- },
16
- "license": "MIT",
17
19
  "sideEffects": false,
18
- "type": "module",
19
20
  "exports": {
20
21
  ".": {
21
22
  "import": "./dist/index.mjs",
@@ -33,49 +34,53 @@
33
34
  "dev": "vitest",
34
35
  "demo": "vite dev playground",
35
36
  "demo:dev": "pnpm demo --config test/vite.config.mjs",
36
- "lint": "pnpm lint:all:eslint && pnpm lint:all:prettier",
37
- "lint:all:eslint": "pnpm lint:eslint --ext .ts,.js,.mjs,.cjs .",
38
- "lint:all:prettier": "pnpm lint:prettier \"{src,test}/**/*.{js,json,ts}\"",
39
- "lint:eslint": "eslint --fix",
40
- "lint:prettier": "prettier --write --loglevel warn",
41
- "prepare": "husky install && pnpm build",
37
+ "lint": "eslint --fix .",
38
+ "prepare": "simple-git-hooks install && pnpm build",
42
39
  "prepublishOnly": "pnpm lint && pnpm test",
43
40
  "release": "pnpm test && bumpp && npm publish",
44
41
  "test": "vitest run"
45
42
  },
46
43
  "dependencies": {
47
- "@capsizecss/metrics": "^1.1.1",
48
- "@capsizecss/unpack": "^1.0.0",
49
- "magic-regexp": "^0.7.0",
50
- "magic-string": "^0.30.0",
51
- "pathe": "^1.1.0",
52
- "ufo": "^1.1.1",
53
- "unplugin": "^1.3.1"
44
+ "@capsizecss/metrics": "^2.1.1",
45
+ "@capsizecss/unpack": "^2.0.1",
46
+ "magic-regexp": "^0.8.0",
47
+ "magic-string": "^0.30.8",
48
+ "pathe": "^1.1.2",
49
+ "ufo": "^1.4.0",
50
+ "unplugin": "^1.8.3"
54
51
  },
55
52
  "devDependencies": {
53
+ "@antfu/eslint-config": "^2.8.0",
56
54
  "@nuxtjs/eslint-config-typescript": "latest",
57
- "@types/node": "18.16.16",
58
- "@types/serve-handler": "6.1.1",
59
- "@typescript-eslint/eslint-plugin": "5.59.8",
60
- "@typescript-eslint/parser": "5.59.8",
61
- "@vitest/coverage-v8": "0.32.0",
62
- "bumpp": "9.1.1",
63
- "eslint": "8.42.0",
64
- "eslint-config-prettier": "8.8.0",
55
+ "@types/node": "20.11.25",
56
+ "@types/serve-handler": "6.1.4",
57
+ "@typescript-eslint/eslint-plugin": "7.1.1",
58
+ "@typescript-eslint/parser": "7.1.1",
59
+ "@vitest/coverage-v8": "1.3.1",
60
+ "bumpp": "9.4.0",
61
+ "eslint": "8.57.0",
62
+ "eslint-config-prettier": "9.1.0",
65
63
  "eslint-plugin-prettier": "latest",
66
- "execa": "7.1.1",
67
- "get-port-please": "3.0.1",
68
- "husky": "latest",
69
- "lint-staged": "13.2.2",
64
+ "execa": "8.0.1",
65
+ "get-port-please": "3.1.2",
66
+ "lint-staged": "15.2.2",
70
67
  "prettier": "latest",
71
68
  "serve-handler": "6.1.5",
72
- "typescript": "5.1.3",
69
+ "simple-git-hooks": "^2.10.0",
70
+ "typescript": "5.4.2",
73
71
  "unbuild": "latest",
74
- "vite": "4.3.9",
75
- "vitest": "0.32.0"
72
+ "vite": "5.1.5",
73
+ "vitest": "1.3.1"
76
74
  },
77
75
  "resolutions": {
78
76
  "fontaine": "link:."
79
77
  },
80
- "packageManager": "pnpm@8.6.0"
78
+ "simple-git-hooks": {
79
+ "pre-commit": "npx lint-staged"
80
+ },
81
+ "lint-staged": {
82
+ "*.{js,ts,mjs,cjs,json,.*rc}": [
83
+ "pnpm eslint --fix"
84
+ ]
85
+ }
81
86
  }