fontaine 0.4.1 → 0.6.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
  },
@@ -188,7 +187,7 @@ Published under [MIT License](./LICENCE).
188
187
  [npm-version-href]: https://npmjs.com/package/fontaine
189
188
  [npm-downloads-src]: https://img.shields.io/npm/dm/fontaine?style=flat-square
190
189
  [npm-downloads-href]: https://npmjs.com/package/fontaine
191
- [github-actions-src]: https://img.shields.io/github/workflow/status/unjs/fontaine/ci/main?style=flat-square
192
- [github-actions-href]: https://github.com/unjs/fontaine/actions?query=workflow%3Aci
190
+ [github-actions-src]: https://img.shields.io/github/actions/workflow/status/unjs/fontaine/ci.yml?branch=main&style=flat-square
191
+ [github-actions-href]: https://github.com/unjs/fontaine/actions/workflows/ci.yml
193
192
  [codecov-src]: https://img.shields.io/codecov/c/gh/unjs/fontaine/main?style=flat-square
194
193
  [codecov-href]: https://codecov.io/gh/unjs/fontaine
package/dist/index.cjs CHANGED
@@ -1,46 +1,115 @@
1
1
  'use strict';
2
2
 
3
- const unplugin = require('unplugin');
3
+ const cssTree = require('css-tree');
4
4
  const magicRegexp = require('magic-regexp');
5
- const MagicString = require('magic-string');
6
5
  const node_url = require('node:url');
7
- const unpack = require('@capsizecss/unpack');
8
6
  const metrics = require('@capsizecss/metrics');
7
+ const unpack = require('@capsizecss/unpack');
9
8
  const ufo = require('ufo');
9
+ const MagicString = require('magic-string');
10
10
  const pathe = require('pathe');
11
+ const unplugin = require('unplugin');
11
12
 
12
13
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
13
14
 
14
15
  const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
15
16
 
16
- function* parseFontFace(css) {
17
- const fontFamily = css.match(FAMILY_RE)?.groups.fontFamily;
18
- const family = withoutQuotes(fontFamily?.split(",")[0] || "");
19
- for (const match of css.matchAll(SOURCE_RE)) {
20
- const sources = match.groups.src?.split(",");
21
- for (const entry of sources || []) {
22
- for (const url of entry.matchAll(URL_RE)) {
23
- const source = withoutQuotes(url.groups?.url || "");
24
- if (source) {
25
- yield { family, source };
17
+ function toPercentage(value, fractionDigits = 4) {
18
+ const percentage = value * 100;
19
+ return `${+percentage.toFixed(fractionDigits)}%`;
20
+ }
21
+ function toCSS(properties, indent = 2) {
22
+ return Object.entries(properties).map(([key, value]) => `${" ".repeat(indent)}${key}: ${value};`).join("\n");
23
+ }
24
+ const QUOTES_RE = magicRegexp.createRegExp(
25
+ magicRegexp.charIn(`"'`).at.lineStart().or(magicRegexp.charIn(`"'`).at.lineEnd()),
26
+ ["g"]
27
+ );
28
+ const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
29
+ const genericCSSFamilies = /* @__PURE__ */ new Set([
30
+ "serif",
31
+ "sans-serif",
32
+ "monospace",
33
+ "cursive",
34
+ "fantasy",
35
+ "system-ui",
36
+ "ui-serif",
37
+ "ui-sans-serif",
38
+ "ui-monospace",
39
+ "ui-rounded",
40
+ "emoji",
41
+ "math",
42
+ "fangsong"
43
+ ]);
44
+ const fontProperties = /* @__PURE__ */ new Set(["font-weight", "font-style", "font-stretch"]);
45
+ function parseFontFace(css) {
46
+ const families = [];
47
+ const ast = typeof css === "string" ? cssTree.parse(css, { positions: true }) : css;
48
+ cssTree.walk(ast, {
49
+ visit: "Atrule",
50
+ enter(node) {
51
+ if (node.name !== "font-face")
52
+ return;
53
+ let family;
54
+ const sources = [];
55
+ const properties = {};
56
+ if (node.block) {
57
+ cssTree.walk(node.block, {
58
+ visit: "Declaration",
59
+ enter(declaration) {
60
+ if (declaration.property === "font-family" && declaration.value.type === "Value") {
61
+ for (const child of declaration.value.children) {
62
+ if (child.type === "String") {
63
+ family = withoutQuotes(child.value);
64
+ break;
65
+ }
66
+ if (child.type === "Identifier" && !genericCSSFamilies.has(child.name)) {
67
+ family = child.name;
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ if (fontProperties.has(declaration.property)) {
73
+ if (declaration.value.type === "Value") {
74
+ for (const child of declaration.value.children) {
75
+ const hasValue = !!properties[declaration.property];
76
+ properties[declaration.property] ||= "";
77
+ properties[declaration.property] += (hasValue ? " " : "") + cssTree.generate(child);
78
+ }
79
+ }
80
+ }
81
+ if (declaration.property === "src") {
82
+ cssTree.walk(declaration.value, {
83
+ visit: "Url",
84
+ enter(urlNode) {
85
+ const source = withoutQuotes(urlNode.value);
86
+ if (source) {
87
+ sources.push(source);
88
+ }
89
+ }
90
+ });
91
+ }
92
+ }
93
+ });
94
+ }
95
+ if (family) {
96
+ for (const source of sources) {
97
+ families.push({ index: node.loc.start.offset, family, source, properties });
98
+ }
99
+ if (!sources.length) {
100
+ families.push({ index: node.loc.start.offset, family, properties });
26
101
  }
27
102
  }
28
103
  }
29
- }
30
- yield { family: "", source: "" };
104
+ });
105
+ return families;
31
106
  }
32
- const generateFallbackName = (name) => {
107
+ function generateFallbackName(name) {
33
108
  const firstFamily = withoutQuotes(name.split(",").shift());
34
109
  return `${firstFamily} fallback`;
35
- };
36
- const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
37
- const generateFontFace = (metrics, fallback) => {
38
- const {
39
- name: fallbackName,
40
- font: fallbackFontName,
41
- metrics: fallbackMetrics,
42
- ...properties
43
- } = fallback;
110
+ }
111
+ function generateFontFace(metrics, fallback) {
112
+ const { name: fallbackName, font: fallbackFontName, metrics: fallbackMetrics, ...properties } = fallback;
44
113
  const preferredFontXAvgRatio = metrics.xWidthAvg / metrics.unitsPerEm;
45
114
  const fallbackFontXAvgRatio = fallbackMetrics ? fallbackMetrics.xWidthAvg / fallbackMetrics.unitsPerEm : 1;
46
115
  const sizeAdjust = fallbackMetrics && preferredFontXAvgRatio && fallbackFontXAvgRatio ? preferredFontXAvgRatio / fallbackFontXAvgRatio : 1;
@@ -50,7 +119,7 @@ const generateFontFace = (metrics, fallback) => {
50
119
  const lineGapOverride = metrics.lineGap / adjustedEmSquare;
51
120
  const declaration = {
52
121
  "font-family": JSON.stringify(fallbackName),
53
- src: `local(${JSON.stringify(fallbackFontName)})`,
122
+ "src": `local(${JSON.stringify(fallbackFontName)})`,
54
123
  "size-adjust": toPercentage(sizeAdjust),
55
124
  "ascent-override": toPercentage(ascentOverride),
56
125
  "descent-override": toPercentage(descentOverride),
@@ -61,50 +130,30 @@ const generateFontFace = (metrics, fallback) => {
61
130
  ${toCSS(declaration)}
62
131
  }
63
132
  `;
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
- );
133
+ }
85
134
 
86
135
  const metricCache = {};
87
- const filterRequiredMetrics = ({
88
- ascent,
89
- descent,
90
- lineGap,
91
- unitsPerEm,
92
- xWidthAvg
93
- }) => ({
94
- ascent,
95
- descent,
96
- lineGap,
97
- unitsPerEm,
98
- xWidthAvg
99
- });
136
+ function filterRequiredMetrics({ ascent, descent, lineGap, unitsPerEm, xWidthAvg }) {
137
+ return {
138
+ ascent,
139
+ descent,
140
+ lineGap,
141
+ unitsPerEm,
142
+ xWidthAvg
143
+ };
144
+ }
100
145
  async function getMetricsForFamily(family) {
101
146
  family = withoutQuotes(family);
102
147
  if (family in metricCache)
103
148
  return metricCache[family];
104
149
  try {
105
150
  const name = metrics.fontFamilyToCamelCase(family);
106
- const { entireMetricsCollection } = await import('@capsizecss/metrics/entireMetricsCollection/dist/capsizecss-metrics-entireMetricsCollection.cjs.js');
151
+ const { entireMetricsCollection } = await import('@capsizecss/metrics/entireMetricsCollection');
107
152
  const metrics$1 = entireMetricsCollection[name];
153
+ if (!("descent" in metrics$1)) {
154
+ metricCache[family] = null;
155
+ return null;
156
+ }
108
157
  const filteredMetrics = filterRequiredMetrics(metrics$1);
109
158
  metricCache[family] = filteredMetrics;
110
159
  return filteredMetrics;
@@ -113,114 +162,114 @@ async function getMetricsForFamily(family) {
113
162
  return null;
114
163
  }
115
164
  }
165
+ const urlRequestCache = /* @__PURE__ */ new Map();
116
166
  async function readMetrics(_source) {
117
167
  const source = typeof _source !== "string" && "href" in _source ? _source.href : _source;
118
- if (source in metricCache) {
119
- return Promise.resolve(metricCache[source]);
120
- }
168
+ if (source in metricCache)
169
+ return metricCache[source];
121
170
  const { protocol } = ufo.parseURL(source);
122
171
  if (!protocol)
123
172
  return null;
124
- const metrics = protocol === "file:" ? await unpack.fromFile(node_url.fileURLToPath(source)) : await unpack.fromUrl(source);
173
+ let metrics;
174
+ if (protocol === "file:") {
175
+ metrics = await unpack.fromFile(node_url.fileURLToPath(source));
176
+ } else {
177
+ if (urlRequestCache.has(source)) {
178
+ metrics = await urlRequestCache.get(source);
179
+ } else {
180
+ const requestPromise = unpack.fromUrl(source);
181
+ urlRequestCache.set(source, requestPromise);
182
+ metrics = await requestPromise;
183
+ }
184
+ }
125
185
  const filteredMetrics = filterRequiredMetrics(metrics);
126
186
  metricCache[source] = filteredMetrics;
127
187
  return filteredMetrics;
128
188
  }
129
189
 
130
190
  const supportedExtensions = ["woff2", "woff", "ttf"];
131
- const FontaineTransform = unplugin.createUnplugin(
132
- (options) => {
133
- const cssContext = options.css = options.css || {};
134
- cssContext.value = "";
135
- const resolvePath = options.resolvePath || ((id) => id);
136
- const fallbackName = options.fallbackName || options.overrideName || generateFallbackName;
137
- const skipFontFaceGeneration = options.skipFontFaceGeneration || (() => false);
138
- function readMetricsFromId(path, importer) {
139
- const resolvedPath = pathe.isAbsolute(importer) && path.startsWith(".") ? pathe.join(importer, path) : resolvePath(path);
140
- return readMetrics(resolvedPath);
141
- }
142
- return {
143
- name: "fontaine-transform",
144
- enforce: "pre",
145
- transformInclude(id) {
146
- const { pathname } = ufo.parseURL(id);
147
- return CSS_RE.test(pathname) || CSS_RE.test(id);
148
- },
149
- async transform(code, id) {
150
- const s = new MagicString__default(code);
151
- const faceRanges = [];
152
- for (const match of code.matchAll(FONT_FACE_RE)) {
153
- const matchContent = match[0];
154
- if (match.index === void 0 || !matchContent)
191
+ const CSS_RE = magicRegexp.createRegExp(
192
+ magicRegexp.exactly(".").and(magicRegexp.anyOf("sass", "css", "scss")).at.lineEnd()
193
+ );
194
+ const RELATIVE_RE = magicRegexp.createRegExp(
195
+ magicRegexp.exactly(".").or("..").and(magicRegexp.anyOf("/", "\\")).at.lineStart()
196
+ );
197
+ const FontaineTransform = unplugin.createUnplugin((options) => {
198
+ const cssContext = options.css = options.css || {};
199
+ cssContext.value = "";
200
+ const resolvePath = options.resolvePath || ((id) => id);
201
+ const fallbackName = options.fallbackName || options.overrideName || generateFallbackName;
202
+ const skipFontFaceGeneration = options.skipFontFaceGeneration || (() => false);
203
+ function readMetricsFromId(path, importer) {
204
+ const resolvedPath = pathe.isAbsolute(importer) && RELATIVE_RE.test(path) ? new URL(path, node_url.pathToFileURL(importer)) : resolvePath(path);
205
+ return readMetrics(resolvedPath);
206
+ }
207
+ return {
208
+ name: "fontaine-transform",
209
+ enforce: "pre",
210
+ transformInclude(id) {
211
+ const { pathname } = ufo.parseURL(id);
212
+ return CSS_RE.test(pathname) || CSS_RE.test(id);
213
+ },
214
+ async transform(code, id) {
215
+ const s = new MagicString__default(code);
216
+ const ast = cssTree.parse(code, { positions: true });
217
+ for (const { family, source, index, properties } of parseFontFace(ast)) {
218
+ if (!supportedExtensions.some((e) => source?.endsWith(e)))
219
+ continue;
220
+ if (skipFontFaceGeneration(fallbackName(family)))
221
+ continue;
222
+ const metrics = await getMetricsForFamily(family) || source && await readMetricsFromId(source, id).catch(() => null);
223
+ if (!metrics)
224
+ continue;
225
+ for (let i = options.fallbacks.length - 1; i >= 0; i--) {
226
+ const fallback = options.fallbacks[i];
227
+ const fallbackMetrics = await getMetricsForFamily(fallback);
228
+ if (!fallbackMetrics)
155
229
  continue;
156
- faceRanges.push([match.index, match.index + matchContent.length]);
157
- for (const { family, source } of parseFontFace(matchContent)) {
230
+ const fontFace = generateFontFace(metrics, {
231
+ name: fallbackName(family),
232
+ font: fallback,
233
+ metrics: fallbackMetrics,
234
+ ...properties
235
+ });
236
+ cssContext.value += fontFace;
237
+ s.appendLeft(index, fontFace);
238
+ }
239
+ }
240
+ cssTree.walk(ast, {
241
+ visit: "Declaration",
242
+ enter(node) {
243
+ if (node.property !== "font-family")
244
+ return;
245
+ if (this.atrule && this.atrule.name === "font-face")
246
+ return;
247
+ if (node.value.type !== "Value")
248
+ return;
249
+ for (const child of node.value.children) {
250
+ let family;
251
+ if (child.type === "String") {
252
+ family = withoutQuotes(child.value);
253
+ } else if (child.type === "Identifier" && child.name !== "inherit") {
254
+ family = child.name;
255
+ }
158
256
  if (!family)
159
257
  continue;
160
- if (!supportedExtensions.some((e) => source?.endsWith(e)))
161
- continue;
162
- if (skipFontFaceGeneration(fallbackName(family)))
163
- continue;
164
- const metrics = await getMetricsForFamily(family) || source && await readMetricsFromId(source, id).catch(() => null);
165
- if (!metrics) {
166
- continue;
167
- }
168
- for (let i = options.fallbacks.length - 1; i >= 0; i--) {
169
- const fallback = options.fallbacks[i];
170
- const fallbackMetrics = await getMetricsForFamily(fallback);
171
- if (!fallbackMetrics) {
172
- continue;
173
- }
174
- const fontFace = generateFontFace(metrics, {
175
- name: fallbackName(family),
176
- font: fallback,
177
- metrics: fallbackMetrics
178
- });
179
- cssContext.value += fontFace;
180
- s.appendLeft(match.index, fontFace);
181
- }
258
+ s.appendRight(child.loc.end.offset, `, "${fallbackName(family)}"`);
259
+ return;
182
260
  }
183
261
  }
184
- for (const match of code.matchAll(FONT_FAMILY_RE)) {
185
- const { index, 0: matchContent } = match;
186
- if (index === void 0 || !matchContent)
187
- continue;
188
- if (faceRanges.some(([start, end]) => index > start && index < end))
189
- continue;
190
- const families = matchContent.split(",").map((f) => f.trim()).filter((f) => !f.startsWith("var("));
191
- if (!families.length || families[0] === "inherit")
192
- continue;
193
- s.overwrite(
194
- index,
195
- index + matchContent.length,
196
- " " + [
197
- families[0],
198
- `"${generateFallbackName(families[0])}"`,
199
- ...families.slice(1)
200
- ].join(", ")
201
- );
202
- }
203
- if (s.hasChanged()) {
204
- return {
205
- code: s.toString(),
206
- map: options.sourcemap ? s.generateMap({ source: id, includeContent: true }) : void 0
207
- };
208
- }
262
+ });
263
+ if (s.hasChanged()) {
264
+ return {
265
+ code: s.toString(),
266
+ /* v8 ignore next 3 */
267
+ map: options.sourcemap ? s.generateMap({ source: id, includeContent: true }) : void 0
268
+ };
209
269
  }
210
- };
211
- }
212
- );
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
- );
270
+ }
271
+ };
272
+ });
224
273
 
225
274
  exports.FontaineTransform = FontaineTransform;
226
275
  exports.generateFallbackName = generateFallbackName;
package/dist/index.d.cts CHANGED
@@ -1,32 +1,104 @@
1
- import * as unplugin from 'unplugin';
2
1
  import { Font } from '@capsizecss/unpack';
2
+ import * as unplugin from 'unplugin';
3
+
4
+ /**
5
+ * Generates a fallback name based on the first font family specified in the input string.
6
+ * @param {string} name - The full font family string.
7
+ * @returns {string} - The fallback font name.
8
+ */
9
+ declare function generateFallbackName(name: string): string;
10
+ interface FallbackOptions {
11
+ /**
12
+ * The name of the fallback font.
13
+ */
14
+ name: string;
15
+ /**
16
+ * The fallback font family name.
17
+ */
18
+ font: string;
19
+ /**
20
+ * Metrics for fallback face calculations.
21
+ * @optional
22
+ */
23
+ metrics?: FontFaceMetrics;
24
+ /**
25
+ * Additional properties that may be included dynamically
26
+ */
27
+ [key: string]: any;
28
+ }
29
+ type FontFaceMetrics = Pick<Font, 'ascent' | 'descent' | 'lineGap' | 'unitsPerEm' | 'xWidthAvg'>;
30
+ /**
31
+ * Generates a CSS `@font-face' declaration for a font, taking fallback and resizing into account.
32
+ * @param {FontFaceMetrics} metrics - The metrics of the preferred font. See {@link FontFaceMetrics}.
33
+ * @param {FallbackOptions} fallback - The fallback options, including name, font and optional metrics. See {@link FallbackOptions}.
34
+ * @returns {string} - The full `@font-face` CSS declaration.
35
+ */
36
+ declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
37
+
38
+ /**
39
+ * Retrieves the font metrics for a given font family from the metrics collection. Uses caching to avoid redundant calculations.
40
+ * @param {string} family - The name of the font family for which metrics are requested.
41
+ * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves with the filtered font metrics or null if not found. See {@link FontFaceMetrics}.
42
+ * @async
43
+ */
44
+ declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
45
+ /**
46
+ * Reads font metrics from a specified source URL or file path. This function supports both local files and remote URLs.
47
+ * It caches the results to optimise subsequent requests for the same source.
48
+ * @param {URL | string} _source - The source URL or local file path from which to read the font metrics.
49
+ * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves to the filtered font metrics or null if the source cannot be processed.
50
+ * @async
51
+ */
52
+ declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
3
53
 
4
54
  interface FontaineTransformOptions {
55
+ /**
56
+ * Configuration options for the CSS transformation.
57
+ * @optional
58
+ */
5
59
  css?: {
60
+ /**
61
+ * Holds the current value of the CSS being transformed.
62
+ * @optional
63
+ */
6
64
  value?: string;
7
65
  };
66
+ /**
67
+ * An array of fallback font family names to use.
68
+ */
8
69
  fallbacks: string[];
70
+ /**
71
+ * Function to resolve a given path to a valid URL or local path.
72
+ * This is typically used to resolve font file paths.
73
+ * @optional
74
+ */
9
75
  resolvePath?: (path: string) => string | URL;
76
+ /**
77
+ * A function to determine whether to skip font face generation for a given fallback name.
78
+ * @optional
79
+ */
10
80
  skipFontFaceGeneration?: (fallbackName: string) => boolean;
11
- /** this should produce an unquoted font family name */
81
+ /**
82
+ * Function to generate an unquoted font family name to use as a fallback.
83
+ * This should return a valid CSS font family name and should not include quotes.
84
+ * @optional
85
+ */
12
86
  fallbackName?: (name: string) => string;
13
87
  /** @deprecated use fallbackName */
14
88
  overrideName?: (name: string) => string;
89
+ /**
90
+ * Specifies whether to create a source map for the transformation.
91
+ * @optional
92
+ */
15
93
  sourcemap?: boolean;
16
94
  }
95
+ /**
96
+ * Transforms CSS files to include font fallbacks.
97
+ *
98
+ * @param options - The transformation options. See {@link FontaineTransformOptions}.
99
+ * @returns The unplugin instance.
100
+ */
17
101
  declare const FontaineTransform: unplugin.UnpluginInstance<FontaineTransformOptions, boolean>;
18
102
 
19
- declare const 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 const 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 };
103
+ export { FontaineTransform, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics };
104
+ export type { FontaineTransformOptions };