fontaine 0.8.2 → 1.0.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/dist/index.cjs CHANGED
@@ -21,10 +21,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- const require_metrics = require("./metrics-ChAPPk2j.cjs");
24
+ const require_metrics = require("./metrics-CS5CISMK.cjs");
25
25
  let css_tree = require("css-tree");
26
- let magic_regexp = require("magic-regexp");
27
- let pathe = require("pathe");
26
+ let node_path = require("node:path");
28
27
  let node_url = require("node:url");
29
28
  let node_fs_promises = require("node:fs/promises");
30
29
  let node_module = require("node:module");
@@ -37,9 +36,9 @@ const supportedExtensions = [
37
36
  "woff",
38
37
  "ttf"
39
38
  ];
40
- const CSS_RE = (0, magic_regexp.createRegExp)((0, magic_regexp.exactly)(".").and((0, magic_regexp.anyOf)("sass", "css", "scss")).and((0, magic_regexp.exactly)("?").and((0, magic_regexp.oneOrMore)(magic_regexp.char)).optionally()).at.lineEnd());
41
- const RELATIVE_RE = (0, magic_regexp.createRegExp)((0, magic_regexp.exactly)(".").or("..").and((0, magic_regexp.anyOf)("/", "\\")).at.lineStart());
42
- const SCSS_RE = (0, magic_regexp.createRegExp)((0, magic_regexp.exactly)(".").and((0, magic_regexp.anyOf)("sass", "scss")).and((0, magic_regexp.exactly)("?").and((0, magic_regexp.oneOrMore)(magic_regexp.char)).optionally()).at.lineEnd());
39
+ const CSS_RE = /\.(?:sass|css|scss)(?:\?.+)?$/;
40
+ const RELATIVE_RE = /^(?:\.|\.\.)(?:\/|\\)/;
41
+ const SCSS_RE = /\.(?:sass|scss)(?:\?.+)?$/;
43
42
  /**
44
43
  * Replaces `//` line comments with spaces, preserving offsets.
45
44
  *
@@ -105,7 +104,7 @@ function extractCssImports(ast) {
105
104
  }
106
105
  function resolveCssImport(specifier, importer) {
107
106
  try {
108
- if (RELATIVE_RE.test(specifier) || (0, pathe.isAbsolute)(specifier)) return (0, node_url.fileURLToPath)(new URL(specifier, (0, node_url.pathToFileURL)(importer)));
107
+ if (RELATIVE_RE.test(specifier) || (0, node_path.isAbsolute)(specifier)) return (0, node_url.fileURLToPath)(new URL(specifier, (0, node_url.pathToFileURL)(importer)));
109
108
  return (0, node_module.createRequire)(importer).resolve(specifier.replace(/^~/, ""));
110
109
  } catch {
111
110
  return;
@@ -120,7 +119,6 @@ function resolveCssImport(specifier, importer) {
120
119
  const FontaineTransform = (0, unplugin.createUnplugin)((options) => {
121
120
  const cssContext = options.css = options.css || {};
122
121
  cssContext.value = "";
123
- const resolvePath = options.resolvePath || ((id) => id);
124
122
  const fallbackName = options.fallbackName || options.overrideName || require_metrics.generateFallbackName;
125
123
  const skipFontFaceGeneration = options.skipFontFaceGeneration || (() => false);
126
124
  return {
@@ -137,7 +135,7 @@ const FontaineTransform = (0, unplugin.createUnplugin)((options) => {
137
135
  importer: id,
138
136
  prefix: ""
139
137
  }));
140
- if ((0, pathe.isAbsolute)(id)) {
138
+ if ((0, node_path.isAbsolute)(id)) {
141
139
  const imports = extractCssImports(ast);
142
140
  const insertionIndex = imports.length ? Math.max(...imports.map((i) => i.end)) : 0;
143
141
  const seen = /* @__PURE__ */ new Set([id]);
@@ -169,7 +167,7 @@ const FontaineTransform = (0, unplugin.createUnplugin)((options) => {
169
167
  const source = rawSource && require_metrics.withoutQueryOrFragment(rawSource);
170
168
  if (!supportedExtensions.some((e) => source?.endsWith(e))) continue;
171
169
  if (skipFontFaceGeneration(fallbackName(family))) continue;
172
- const metrics = await require_metrics.getMetricsForFamily(family) || source && await require_metrics.readMetricsForSource(source, importer, resolvePath).catch(() => null);
170
+ const metrics = await require_metrics.getMetricsForFamily(family) || source && await require_metrics.readMetricsForSource(source, importer, options.resolvePath).catch(() => null);
173
171
  /* v8 ignore next 2 */
174
172
  if (!metrics) continue;
175
173
  const familyFallbacks = require_metrics.resolveCategoryFallbacks({
package/dist/index.d.cts CHANGED
@@ -8,7 +8,7 @@ import { createUnplugin } from "unplugin";
8
8
  * @param {string} name - The full font family string.
9
9
  * @returns {string} - The fallback font name.
10
10
  */
11
- declare function generateFallbackName(name: string): string;
11
+ export declare function generateFallbackName(name: string): string;
12
12
  interface FallbackOptions {
13
13
  /**
14
14
  * The name of the fallback font.
@@ -37,7 +37,7 @@ type FontFaceMetrics = Pick<Font, "ascent" | "descent" | "lineGap" | "unitsPerEm
37
37
  * @param {FallbackOptions} fallback - The fallback options, including name, font and optional metrics. See {@link FallbackOptions}.
38
38
  * @returns {string} - The full `@font-face` CSS declaration.
39
39
  */
40
- declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
40
+ export declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
41
41
  //#endregion
42
42
  //#region src/metrics.d.ts
43
43
  /**
@@ -46,15 +46,16 @@ declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOp
46
46
  * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves with the filtered font metrics or null if not found. See {@link FontFaceMetrics}.
47
47
  * @async
48
48
  */
49
- declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
49
+ export declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
50
50
  /**
51
- * Reads font metrics from a specified source URL or file path. This function supports both local files and remote URLs.
51
+ * Reads font metrics from a source URL, which may be a `file:` URL or a remote one. A string
52
+ * that is not a URL, such as a bare path or a root-relative one, resolves to `null`.
52
53
  * It caches the results to optimise subsequent requests for the same source.
53
- * @param {URL | string} _source - The source URL or local file path from which to read the font metrics.
54
+ * @param {URL | string} _source - The source URL from which to read the font metrics.
54
55
  * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves to the filtered font metrics or null if the source cannot be processed.
55
56
  * @async
56
57
  */
57
- declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
58
+ export declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
58
59
  //#endregion
59
60
  //#region src/transform.d.ts
60
61
  interface FontaineTransformOptions {
@@ -83,8 +84,8 @@ interface FontaineTransformOptions {
83
84
  */
84
85
  categoryFallbacks?: Partial<Record<FontCategory, string[]>>;
85
86
  /**
86
- * Function to resolve a given path to a valid URL or local path.
87
- * This is typically used to resolve font file paths.
87
+ * Function to resolve a font `src` value declared in a stylesheet to the font file it
88
+ * refers to, as either a URL or an absolute path on disk.
88
89
  * @optional
89
90
  */
90
91
  resolvePath?: (path: string) => string | URL;
@@ -113,6 +114,6 @@ interface FontaineTransformOptions {
113
114
  * @param options - The transformation options. See {@link FontaineTransformOptions}.
114
115
  * @returns The unplugin instance.
115
116
  */
116
- declare const FontaineTransform: ReturnType<typeof createUnplugin<FontaineTransformOptions>>;
117
+ export declare const FontaineTransform: ReturnType<typeof createUnplugin<FontaineTransformOptions>>;
117
118
  //#endregion
118
- export { DEFAULT_CATEGORY_FALLBACKS, type FontCategory, FontaineTransform, type FontaineTransformOptions, type ResolveCategoryFallbacksOptions, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics, resolveCategoryFallbacks };
119
+ export { DEFAULT_CATEGORY_FALLBACKS, type FontCategory, type FontaineTransformOptions, type ResolveCategoryFallbacksOptions, resolveCategoryFallbacks };
package/dist/index.d.mts CHANGED
@@ -8,7 +8,7 @@ import { createUnplugin } from "unplugin";
8
8
  * @param {string} name - The full font family string.
9
9
  * @returns {string} - The fallback font name.
10
10
  */
11
- declare function generateFallbackName(name: string): string;
11
+ export declare function generateFallbackName(name: string): string;
12
12
  interface FallbackOptions {
13
13
  /**
14
14
  * The name of the fallback font.
@@ -37,7 +37,7 @@ type FontFaceMetrics = Pick<Font, "ascent" | "descent" | "lineGap" | "unitsPerEm
37
37
  * @param {FallbackOptions} fallback - The fallback options, including name, font and optional metrics. See {@link FallbackOptions}.
38
38
  * @returns {string} - The full `@font-face` CSS declaration.
39
39
  */
40
- declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
40
+ export declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOptions): string;
41
41
  //#endregion
42
42
  //#region src/metrics.d.ts
43
43
  /**
@@ -46,15 +46,16 @@ declare function generateFontFace(metrics: FontFaceMetrics, fallback: FallbackOp
46
46
  * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves with the filtered font metrics or null if not found. See {@link FontFaceMetrics}.
47
47
  * @async
48
48
  */
49
- declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
49
+ export declare function getMetricsForFamily(family: string): Promise<FontFaceMetrics | null>;
50
50
  /**
51
- * Reads font metrics from a specified source URL or file path. This function supports both local files and remote URLs.
51
+ * Reads font metrics from a source URL, which may be a `file:` URL or a remote one. A string
52
+ * that is not a URL, such as a bare path or a root-relative one, resolves to `null`.
52
53
  * It caches the results to optimise subsequent requests for the same source.
53
- * @param {URL | string} _source - The source URL or local file path from which to read the font metrics.
54
+ * @param {URL | string} _source - The source URL from which to read the font metrics.
54
55
  * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves to the filtered font metrics or null if the source cannot be processed.
55
56
  * @async
56
57
  */
57
- declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
58
+ export declare function readMetrics(_source: URL | string): Promise<FontFaceMetrics | null>;
58
59
  //#endregion
59
60
  //#region src/transform.d.ts
60
61
  interface FontaineTransformOptions {
@@ -83,8 +84,8 @@ interface FontaineTransformOptions {
83
84
  */
84
85
  categoryFallbacks?: Partial<Record<FontCategory, string[]>>;
85
86
  /**
86
- * Function to resolve a given path to a valid URL or local path.
87
- * This is typically used to resolve font file paths.
87
+ * Function to resolve a font `src` value declared in a stylesheet to the font file it
88
+ * refers to, as either a URL or an absolute path on disk.
88
89
  * @optional
89
90
  */
90
91
  resolvePath?: (path: string) => string | URL;
@@ -113,6 +114,6 @@ interface FontaineTransformOptions {
113
114
  * @param options - The transformation options. See {@link FontaineTransformOptions}.
114
115
  * @returns The unplugin instance.
115
116
  */
116
- declare const FontaineTransform: ReturnType<typeof createUnplugin<FontaineTransformOptions>>;
117
+ export declare const FontaineTransform: ReturnType<typeof createUnplugin<FontaineTransformOptions>>;
117
118
  //#endregion
118
- export { DEFAULT_CATEGORY_FALLBACKS, type FontCategory, FontaineTransform, type FontaineTransformOptions, type ResolveCategoryFallbacksOptions, generateFallbackName, generateFontFace, getMetricsForFamily, readMetrics, resolveCategoryFallbacks };
119
+ export { DEFAULT_CATEGORY_FALLBACKS, type FontCategory, type FontaineTransformOptions, type ResolveCategoryFallbacksOptions, resolveCategoryFallbacks };
package/dist/index.mjs CHANGED
@@ -1,8 +1,7 @@
1
- import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, i as DEFAULT_CATEGORY_FALLBACKS, l as genericCSSFamilies, n as readMetrics, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-DgPzfV2U.mjs";
1
+ import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, i as DEFAULT_CATEGORY_FALLBACKS, l as genericCSSFamilies, n as readMetrics, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-BfrxJdKT.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { parse, walk } from "css-tree";
4
- import { anyOf, char, createRegExp, exactly, oneOrMore } from "magic-regexp";
5
- import { isAbsolute } from "pathe";
4
+ import { isAbsolute } from "node:path";
6
5
  import { fileURLToPath, pathToFileURL } from "node:url";
7
6
  import { readFile } from "node:fs/promises";
8
7
  import MagicString from "magic-string";
@@ -13,9 +12,9 @@ const supportedExtensions = [
13
12
  "woff",
14
13
  "ttf"
15
14
  ];
16
- const CSS_RE = createRegExp(exactly(".").and(anyOf("sass", "css", "scss")).and(exactly("?").and(oneOrMore(char)).optionally()).at.lineEnd());
17
- const RELATIVE_RE = createRegExp(exactly(".").or("..").and(anyOf("/", "\\")).at.lineStart());
18
- const SCSS_RE = createRegExp(exactly(".").and(anyOf("sass", "scss")).and(exactly("?").and(oneOrMore(char)).optionally()).at.lineEnd());
15
+ const CSS_RE = /\.(?:sass|css|scss)(?:\?.+)?$/;
16
+ const RELATIVE_RE = /^(?:\.|\.\.)(?:\/|\\)/;
17
+ const SCSS_RE = /\.(?:sass|scss)(?:\?.+)?$/;
19
18
  /**
20
19
  * Replaces `//` line comments with spaces, preserving offsets.
21
20
  *
@@ -96,7 +95,6 @@ function resolveCssImport(specifier, importer) {
96
95
  const FontaineTransform = createUnplugin((options) => {
97
96
  const cssContext = options.css = options.css || {};
98
97
  cssContext.value = "";
99
- const resolvePath = options.resolvePath || ((id) => id);
100
98
  const fallbackName = options.fallbackName || options.overrideName || generateFallbackName;
101
99
  const skipFontFaceGeneration = options.skipFontFaceGeneration || (() => false);
102
100
  return {
@@ -145,7 +143,7 @@ const FontaineTransform = createUnplugin((options) => {
145
143
  const source = rawSource && withoutQueryOrFragment(rawSource);
146
144
  if (!supportedExtensions.some((e) => source?.endsWith(e))) continue;
147
145
  if (skipFontFaceGeneration(fallbackName(family))) continue;
148
- const metrics = await getMetricsForFamily(family) || source && await readMetricsForSource(source, importer, resolvePath).catch(() => null);
146
+ const metrics = await getMetricsForFamily(family) || source && await readMetricsForSource(source, importer, options.resolvePath).catch(() => null);
149
147
  /* v8 ignore next 2 */
150
148
  if (!metrics) continue;
151
149
  const familyFallbacks = resolveCategoryFallbacks({
@@ -1,7 +1,5 @@
1
1
  import { generate, parse, walk } from "css-tree";
2
- import { char, charIn, createRegExp, oneOrMore } from "magic-regexp";
3
- import { isAbsolute } from "pathe";
4
- import { hasProtocol, parseURL } from "ufo";
2
+ import { isAbsolute } from "node:path";
5
3
  import { fileURLToPath, pathToFileURL } from "node:url";
6
4
  import { fromUrl } from "@capsizecss/unpack";
7
5
  import { fromFile } from "@capsizecss/unpack/fs";
@@ -12,9 +10,9 @@ function toPercentage(value, fractionDigits = 4) {
12
10
  function toCSS(properties, indent = 2) {
13
11
  return Object.entries(properties).map(([key, value]) => `${" ".repeat(indent)}${key}: ${value};`).join("\n");
14
12
  }
15
- const QUOTES_RE = createRegExp(charIn("\"'").at.lineStart().or(charIn("\"'").at.lineEnd()), ["g"]);
13
+ const QUOTES_RE = /(?:^["']|["']$)/g;
16
14
  const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
17
- const QUERY_OR_FRAGMENT_RE = createRegExp(charIn("?#").and(oneOrMore(char).optionally()).at.lineEnd());
15
+ const QUERY_OR_FRAGMENT_RE = /[?#](?:.+)?$/;
18
16
  /** Removes any `?query` or `#fragment` suffix, which is not part of the file a URL points to. */
19
17
  function withoutQueryOrFragment(source) {
20
18
  return source.replace(QUERY_OR_FRAGMENT_RE, "");
@@ -28,7 +26,7 @@ function withoutQueryOrFragment(source) {
28
26
  * resolving against the stylesheet finds nothing.
29
27
  */
30
28
  function isStylesheetRelative(source) {
31
- return !hasProtocol(source, { acceptRelative: true }) && !isAbsolute(source);
29
+ return !source.startsWith("/") && !URL.canParse(source);
32
30
  }
33
31
  const cssWideKeywords = /* @__PURE__ */ new Set([
34
32
  "inherit",
@@ -310,19 +308,20 @@ async function getMetricsForFamily(family) {
310
308
  }
311
309
  const urlRequestCache = /* @__PURE__ */ new Map();
312
310
  /**
313
- * Reads font metrics from a specified source URL or file path. This function supports both local files and remote URLs.
311
+ * Reads font metrics from a source URL, which may be a `file:` URL or a remote one. A string
312
+ * that is not a URL, such as a bare path or a root-relative one, resolves to `null`.
314
313
  * It caches the results to optimise subsequent requests for the same source.
315
- * @param {URL | string} _source - The source URL or local file path from which to read the font metrics.
314
+ * @param {URL | string} _source - The source URL from which to read the font metrics.
316
315
  * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves to the filtered font metrics or null if the source cannot be processed.
317
316
  * @async
318
317
  */
319
318
  async function readMetrics(_source) {
320
319
  const source = typeof _source !== "string" && "href" in _source ? _source.href : _source;
321
320
  if (source in metricCache) return metricCache[source] ?? null;
322
- const { protocol } = parseURL(source);
323
- if (!protocol) return null;
321
+ const url = typeof _source === "string" ? isAbsolute(_source) ? null : URL.parse(_source) : _source;
322
+ if (!url) return null;
324
323
  let metrics;
325
- if (protocol === "file:") metrics = await fromFile(fileURLToPath(source));
324
+ if (url.protocol === "file:") metrics = await fromFile(fileURLToPath(source));
326
325
  else if (urlRequestCache.has(source)) metrics = await urlRequestCache.get(source);
327
326
  else {
328
327
  const requestPromise = fromUrl(source);
@@ -339,13 +338,19 @@ async function readMetrics(_source) {
339
338
  * A scheme-less, non-rooted URL is resolved against the stylesheet first, then handed to
340
339
  * `resolvePath` if that yields no metrics: bare package specifiers and webpack's `~` prefix
341
340
  * look identical to stylesheet-relative paths, and only the caller's resolver can map them.
341
+ *
342
+ * `resolvePath` returns a location rather than a URL, so an absolute path it returns is a file
343
+ * on disk. Without a resolver `source` is still the URL the stylesheet declared, where a leading
344
+ * slash means the document root.
342
345
  */
343
346
  async function readMetricsForSource(source, importer, resolvePath) {
344
347
  if (importer && isAbsolute(importer) && isStylesheetRelative(source)) {
345
348
  const metrics = await readMetrics(new URL(source, pathToFileURL(importer))).catch(() => null);
346
349
  if (metrics) return metrics;
347
350
  }
348
- return readMetrics(resolvePath(source));
351
+ if (!resolvePath) return readMetrics(source);
352
+ const resolved = resolvePath(source);
353
+ return readMetrics(typeof resolved === "string" && isAbsolute(resolved) ? pathToFileURL(resolved) : resolved);
349
354
  }
350
355
  function fontFamilyToCamelCase(str) {
351
356
  return str.split(/[\s|-]/).filter(Boolean).map((s, i) => `${s.charAt(0)[i > 0 ? "toUpperCase" : "toLowerCase"]()}${s.slice(1)}`).join("");
@@ -1,7 +1,5 @@
1
1
  let css_tree = require("css-tree");
2
- let magic_regexp = require("magic-regexp");
3
- let pathe = require("pathe");
4
- let ufo = require("ufo");
2
+ let node_path = require("node:path");
5
3
  let node_url = require("node:url");
6
4
  let _capsizecss_unpack = require("@capsizecss/unpack");
7
5
  let _capsizecss_unpack_fs = require("@capsizecss/unpack/fs");
@@ -12,9 +10,9 @@ function toPercentage(value, fractionDigits = 4) {
12
10
  function toCSS(properties, indent = 2) {
13
11
  return Object.entries(properties).map(([key, value]) => `${" ".repeat(indent)}${key}: ${value};`).join("\n");
14
12
  }
15
- const QUOTES_RE = (0, magic_regexp.createRegExp)((0, magic_regexp.charIn)("\"'").at.lineStart().or((0, magic_regexp.charIn)("\"'").at.lineEnd()), ["g"]);
13
+ const QUOTES_RE = /(?:^["']|["']$)/g;
16
14
  const withoutQuotes = (str) => str.trim().replace(QUOTES_RE, "");
17
- const QUERY_OR_FRAGMENT_RE = (0, magic_regexp.createRegExp)((0, magic_regexp.charIn)("?#").and((0, magic_regexp.oneOrMore)(magic_regexp.char).optionally()).at.lineEnd());
15
+ const QUERY_OR_FRAGMENT_RE = /[?#](?:.+)?$/;
18
16
  /** Removes any `?query` or `#fragment` suffix, which is not part of the file a URL points to. */
19
17
  function withoutQueryOrFragment(source) {
20
18
  return source.replace(QUERY_OR_FRAGMENT_RE, "");
@@ -28,7 +26,7 @@ function withoutQueryOrFragment(source) {
28
26
  * resolving against the stylesheet finds nothing.
29
27
  */
30
28
  function isStylesheetRelative(source) {
31
- return !(0, ufo.hasProtocol)(source, { acceptRelative: true }) && !(0, pathe.isAbsolute)(source);
29
+ return !source.startsWith("/") && !URL.canParse(source);
32
30
  }
33
31
  const cssWideKeywords = /* @__PURE__ */ new Set([
34
32
  "inherit",
@@ -310,19 +308,20 @@ async function getMetricsForFamily(family) {
310
308
  }
311
309
  const urlRequestCache = /* @__PURE__ */ new Map();
312
310
  /**
313
- * Reads font metrics from a specified source URL or file path. This function supports both local files and remote URLs.
311
+ * Reads font metrics from a source URL, which may be a `file:` URL or a remote one. A string
312
+ * that is not a URL, such as a bare path or a root-relative one, resolves to `null`.
314
313
  * It caches the results to optimise subsequent requests for the same source.
315
- * @param {URL | string} _source - The source URL or local file path from which to read the font metrics.
314
+ * @param {URL | string} _source - The source URL from which to read the font metrics.
316
315
  * @returns {Promise<FontFaceMetrics | null>} - A promise that resolves to the filtered font metrics or null if the source cannot be processed.
317
316
  * @async
318
317
  */
319
318
  async function readMetrics(_source) {
320
319
  const source = typeof _source !== "string" && "href" in _source ? _source.href : _source;
321
320
  if (source in metricCache) return metricCache[source] ?? null;
322
- const { protocol } = (0, ufo.parseURL)(source);
323
- if (!protocol) return null;
321
+ const url = typeof _source === "string" ? (0, node_path.isAbsolute)(_source) ? null : URL.parse(_source) : _source;
322
+ if (!url) return null;
324
323
  let metrics;
325
- if (protocol === "file:") metrics = await (0, _capsizecss_unpack_fs.fromFile)((0, node_url.fileURLToPath)(source));
324
+ if (url.protocol === "file:") metrics = await (0, _capsizecss_unpack_fs.fromFile)((0, node_url.fileURLToPath)(source));
326
325
  else if (urlRequestCache.has(source)) metrics = await urlRequestCache.get(source);
327
326
  else {
328
327
  const requestPromise = (0, _capsizecss_unpack.fromUrl)(source);
@@ -339,13 +338,19 @@ async function readMetrics(_source) {
339
338
  * A scheme-less, non-rooted URL is resolved against the stylesheet first, then handed to
340
339
  * `resolvePath` if that yields no metrics: bare package specifiers and webpack's `~` prefix
341
340
  * look identical to stylesheet-relative paths, and only the caller's resolver can map them.
341
+ *
342
+ * `resolvePath` returns a location rather than a URL, so an absolute path it returns is a file
343
+ * on disk. Without a resolver `source` is still the URL the stylesheet declared, where a leading
344
+ * slash means the document root.
342
345
  */
343
346
  async function readMetricsForSource(source, importer, resolvePath) {
344
- if (importer && (0, pathe.isAbsolute)(importer) && isStylesheetRelative(source)) {
347
+ if (importer && (0, node_path.isAbsolute)(importer) && isStylesheetRelative(source)) {
345
348
  const metrics = await readMetrics(new URL(source, (0, node_url.pathToFileURL)(importer))).catch(() => null);
346
349
  if (metrics) return metrics;
347
350
  }
348
- return readMetrics(resolvePath(source));
351
+ if (!resolvePath) return readMetrics(source);
352
+ const resolved = resolvePath(source);
353
+ return readMetrics(typeof resolved === "string" && (0, node_path.isAbsolute)(resolved) ? (0, node_url.pathToFileURL)(resolved) : resolved);
349
354
  }
350
355
  function fontFamilyToCamelCase(str) {
351
356
  return str.split(/[\s|-]/).filter(Boolean).map((s, i) => `${s.charAt(0)[i > 0 ? "toUpperCase" : "toLowerCase"]()}${s.slice(1)}`).join("");
package/dist/postcss.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_metrics = require("./metrics-ChAPPk2j.cjs");
1
+ const require_metrics = require("./metrics-CS5CISMK.cjs");
2
2
  let css_tree = require("css-tree");
3
3
  //#region src/postcss.ts
4
4
  const supportedExtensions = [
@@ -23,7 +23,6 @@ function isFontFaceRule(node) {
23
23
  return node?.type === "atrule" && node.name.toLowerCase() === "font-face";
24
24
  }
25
25
  function fontaine(options) {
26
- const resolvePath = options.resolvePath || ((id) => id);
27
26
  const fallbackName = options.fallbackName || require_metrics.generateFallbackName;
28
27
  const skipFontFaceGeneration = options.skipFontFaceGeneration || (() => false);
29
28
  return {
@@ -35,7 +34,7 @@ function fontaine(options) {
35
34
  const source = url && require_metrics.withoutQueryOrFragment(url);
36
35
  if (!source || !supportedExtensions.some((e) => source.endsWith(e))) continue;
37
36
  if (skipFontFaceGeneration(fallbackName(family))) continue;
38
- const metrics = await require_metrics.getMetricsForFamily(family) || await require_metrics.readMetricsForSource(source, originatingFile(rule, result), resolvePath).catch(() => null);
37
+ const metrics = await require_metrics.getMetricsForFamily(family) || await require_metrics.readMetricsForSource(source, originatingFile(rule, result), options.resolvePath).catch(() => null);
39
38
  if (!metrics) continue;
40
39
  const familyFallbacks = require_metrics.resolveCategoryFallbacks({
41
40
  fontFamily: family,
@@ -1,7 +1,7 @@
1
1
  import { n as FontCategory } from "./fallbacks-Cj4LUWhi.cjs";
2
2
  import { Plugin } from "postcss";
3
3
  //#region src/postcss.d.ts
4
- interface FontainePostcssOptions {
4
+ export interface FontainePostcssOptions {
5
5
  /**
6
6
  * Font family fallbacks to use.
7
7
  * Can be an array of fallback font family names to use for all fonts,
@@ -16,8 +16,8 @@ interface FontainePostcssOptions {
16
16
  */
17
17
  categoryFallbacks?: Partial<Record<FontCategory, string[]>>;
18
18
  /**
19
- * Function to resolve a given path to a valid URL or local path.
20
- * This is typically used to resolve font file paths.
19
+ * Function to resolve a font `src` value declared in a stylesheet to the font file it
20
+ * refers to, as either a URL or an absolute path on disk.
21
21
  * @optional
22
22
  */
23
23
  resolvePath?: (path: string) => string | URL;
@@ -49,4 +49,4 @@ interface FontainePlugin {
49
49
  }
50
50
  declare const plugin: FontainePlugin;
51
51
  //#endregion
52
- export { FontainePostcssOptions, plugin as default };
52
+ export { plugin as default };
@@ -1,7 +1,7 @@
1
1
  import { n as FontCategory } from "./fallbacks-Cj4LUWhi.mjs";
2
2
  import { Plugin } from "postcss";
3
3
  //#region src/postcss.d.ts
4
- interface FontainePostcssOptions {
4
+ export interface FontainePostcssOptions {
5
5
  /**
6
6
  * Font family fallbacks to use.
7
7
  * Can be an array of fallback font family names to use for all fonts,
@@ -16,8 +16,8 @@ interface FontainePostcssOptions {
16
16
  */
17
17
  categoryFallbacks?: Partial<Record<FontCategory, string[]>>;
18
18
  /**
19
- * Function to resolve a given path to a valid URL or local path.
20
- * This is typically used to resolve font file paths.
19
+ * Function to resolve a font `src` value declared in a stylesheet to the font file it
20
+ * refers to, as either a URL or an absolute path on disk.
21
21
  * @optional
22
22
  */
23
23
  resolvePath?: (path: string) => string | URL;
@@ -49,4 +49,4 @@ interface FontainePlugin {
49
49
  }
50
50
  declare const plugin: FontainePlugin;
51
51
  //#endregion
52
- export { FontainePostcssOptions, plugin as default };
52
+ export { plugin as default };
package/dist/postcss.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, l as genericCSSFamilies, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-DgPzfV2U.mjs";
1
+ import { a as resolveCategoryFallbacks, c as generateFontFace, d as withoutQueryOrFragment, f as withoutQuotes, l as genericCSSFamilies, o as cssWideKeywords, r as readMetricsForSource, s as generateFallbackName, t as getMetricsForFamily, u as parseFontFace } from "./metrics-BfrxJdKT.mjs";
2
2
  import { parse } from "css-tree";
3
3
  //#region src/postcss.ts
4
4
  const supportedExtensions = [
@@ -23,7 +23,6 @@ function isFontFaceRule(node) {
23
23
  return node?.type === "atrule" && node.name.toLowerCase() === "font-face";
24
24
  }
25
25
  function fontaine(options) {
26
- const resolvePath = options.resolvePath || ((id) => id);
27
26
  const fallbackName = options.fallbackName || generateFallbackName;
28
27
  const skipFontFaceGeneration = options.skipFontFaceGeneration || (() => false);
29
28
  return {
@@ -35,7 +34,7 @@ function fontaine(options) {
35
34
  const source = url && withoutQueryOrFragment(url);
36
35
  if (!source || !supportedExtensions.some((e) => source.endsWith(e))) continue;
37
36
  if (skipFontFaceGeneration(fallbackName(family))) continue;
38
- const metrics = await getMetricsForFamily(family) || await readMetricsForSource(source, originatingFile(rule, result), resolvePath).catch(() => null);
37
+ const metrics = await getMetricsForFamily(family) || await readMetricsForSource(source, originatingFile(rule, result), options.resolvePath).catch(() => null);
39
38
  if (!metrics) continue;
40
39
  const familyFallbacks = resolveCategoryFallbacks({
41
40
  fontFamily: family,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fontaine",
3
3
  "type": "module",
4
- "version": "0.8.2",
4
+ "version": "1.0.0",
5
5
  "description": "Automatic font fallback based on font metrics",
6
6
  "author": {
7
7
  "name": "Daniel Roe",
@@ -60,26 +60,24 @@
60
60
  "dependencies": {
61
61
  "@capsizecss/unpack": "^4.0.0",
62
62
  "css-tree": "^3.1.0",
63
- "magic-regexp": "^0.11.0",
64
63
  "magic-string": "^1.0.0",
65
- "pathe": "^2.0.3",
66
- "ufo": "^1.6.1",
67
64
  "unplugin": "^3.0.0"
68
65
  },
69
66
  "devDependencies": {
70
- "@capsizecss/metrics": "4.2.0",
67
+ "@capsizecss/metrics": "4.3.0",
71
68
  "@types/css-tree": "3.2.0",
72
- "@types/node": "24.13.3",
69
+ "@types/node": "24.13.6",
73
70
  "@types/serve-handler": "6.1.4",
74
- "@vitest/coverage-v8": "5.0.0",
75
- "eslint": "10.10.0",
71
+ "@vitest/coverage-v8": "5.0.1",
72
+ "eslint": "10.11.0",
76
73
  "get-port-please": "3.2.0",
77
- "postcss": "8.5.26",
74
+ "magic-regexp": "0.11.0",
75
+ "postcss": "8.5.28",
78
76
  "serve-handler": "6.1.7",
79
- "tsdown": "0.22.14",
77
+ "tsdown": "0.23.0",
80
78
  "typescript": "6.0.3",
81
79
  "vite": "8.3.0",
82
- "vitest": "5.0.0"
80
+ "vitest": "5.0.1"
83
81
  },
84
82
  "scripts": {
85
83
  "build": "tsdown",