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 +9 -10
- package/dist/index.cjs +201 -152
- package/dist/index.d.cts +88 -16
- package/dist/index.d.mts +88 -16
- package/dist/index.d.ts +88 -16
- package/dist/index.mjs +204 -155
- package/package.json +48 -40
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:
|
|
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:
|
|
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
|
|
192
|
-
[github-actions-href]: https://github.com/unjs/fontaine/actions
|
|
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
|
|
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
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
104
|
+
});
|
|
105
|
+
return families;
|
|
31
106
|
}
|
|
32
|
-
|
|
107
|
+
function generateFallbackName(name) {
|
|
33
108
|
const firstFamily = withoutQuotes(name.split(",").shift());
|
|
34
109
|
return `${firstFamily} fallback`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
132
|
-
(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
157
|
-
|
|
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
|
-
|
|
161
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
20
|
-
|
|
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 };
|