@docfonts/fallbacks 0.3.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 +1 -0
- package/dist/data.js +31 -0
- package/dist/fallbacks.js +14 -2
- package/dist/types.d.ts +8 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -86,6 +86,7 @@ Keys are normalized. Use `normalizeFamilyName` for lookups. Rows whose substitut
|
|
|
86
86
|
- `lineBreakSafe` - true when advances preserve line breaks: `metric_safe`, `near_metric`, or monospace `cell_width_only`.
|
|
87
87
|
- `faces` - reviewed face coverage for this evidence row. If any face is `true`, respect it as face-scoped coverage (a row can be Regular-only). If all faces are `false`, the row is **not** face-scoped (e.g. a category fallback whose physical font does have faces) and the face-aware helpers treat it as renderable for any face.
|
|
88
88
|
- `evidenceId` - the stable id for the reviewed evidence row; look the full row up in `SUBSTITUTION_EVIDENCE`.
|
|
89
|
+
- `glyphExceptions` - named glyph-level divergences that qualify this fallback (e.g. one codepoint reflows), or omitted when none. A family lookup carries all of the row's; a face lookup (`getRenderableFallbackForFace`) carries only that face's, so Cambria Regular shows none while Bold Italic shows its grave-accent exception.
|
|
89
90
|
|
|
90
91
|
`cell_width_only` keeps monospace advances stable, but glyph shapes can still differ. A `substitute` can still have a lower-fidelity `verdict` when one face or glyph is qualified. The verdict is the fidelity signal.
|
|
91
92
|
|
package/dist/data.js
CHANGED
|
@@ -645,5 +645,36 @@ export const SUBSTITUTION_EVIDENCE = [
|
|
|
645
645
|
"note": "Bacasime Antique Regular's no-break space (U+00A0) advance diverges ~49% from Baskerville Old Face; lines containing NBSP reflow. Every other Latin-core glyph is advance-identical, which is why this is visual_only with a single named exception, not near_metric."
|
|
646
646
|
}
|
|
647
647
|
]
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
"evidenceId": "cooper-black",
|
|
651
|
+
"logicalFamily": "Cooper Black",
|
|
652
|
+
"physicalFamily": "Caprasimo",
|
|
653
|
+
"verdict": "metric_safe",
|
|
654
|
+
"faces": {
|
|
655
|
+
"regular": true,
|
|
656
|
+
"bold": false,
|
|
657
|
+
"italic": false,
|
|
658
|
+
"boldItalic": false
|
|
659
|
+
},
|
|
660
|
+
"gates": {
|
|
661
|
+
"static": "pass",
|
|
662
|
+
"metric": "pass",
|
|
663
|
+
"layout": "not_run",
|
|
664
|
+
"ship": "not_run"
|
|
665
|
+
},
|
|
666
|
+
"policyAction": "substitute",
|
|
667
|
+
"measurementRefs": [
|
|
668
|
+
"cooper-black_regular__caprasimo#regular#w400#786ab84e#analytic_advance#2026-06-05"
|
|
669
|
+
],
|
|
670
|
+
"exportRule": "preserve_original_name",
|
|
671
|
+
"advance": {
|
|
672
|
+
"meanDelta": 0,
|
|
673
|
+
"maxDelta": 0
|
|
674
|
+
},
|
|
675
|
+
"candidateLicense": "OFL-1.1",
|
|
676
|
+
"faceVerdicts": {
|
|
677
|
+
"regular": "metric_safe"
|
|
678
|
+
}
|
|
648
679
|
}
|
|
649
680
|
];
|
package/dist/fallbacks.js
CHANGED
|
@@ -34,8 +34,17 @@ const BY_LOGICAL = new Map(SUBSTITUTION_EVIDENCE.map((row) => [
|
|
|
34
34
|
* Build the FontFallback for a row known to carry a renderable physical family. `verdict` is passed in
|
|
35
35
|
* so a face-aware caller can supply the per-face verdict (faceVerdicts[face]) instead of the worst-face
|
|
36
36
|
* top-level one - e.g. Cambria regular is metric_safe even though the family rolls up to visual_only.
|
|
37
|
+
* `faceSlot` (a face lookup) scopes the glyph exceptions to that face; omitting it (a family lookup)
|
|
38
|
+
* carries all of the row's. Empty exception sets are dropped so the field is present only when it bites.
|
|
37
39
|
*/
|
|
38
|
-
function buildFallback(row, physicalFamily, verdict) {
|
|
40
|
+
function buildFallback(row, physicalFamily, verdict, faceSlot) {
|
|
41
|
+
// Always hand back a FRESH array - filter() already copies; the family path must copy too, or a
|
|
42
|
+
// consumer mutating it would corrupt the shared evidence row for later lookups.
|
|
43
|
+
const glyphExceptions = faceSlot
|
|
44
|
+
? row.glyphExceptions?.filter((g) => g.slot === faceSlot)
|
|
45
|
+
: row.glyphExceptions
|
|
46
|
+
? [...row.glyphExceptions]
|
|
47
|
+
: undefined;
|
|
39
48
|
return {
|
|
40
49
|
substituteFamily: physicalFamily,
|
|
41
50
|
policyAction: row.policyAction,
|
|
@@ -43,6 +52,9 @@ function buildFallback(row, physicalFamily, verdict) {
|
|
|
43
52
|
lineBreakSafe: LINE_BREAK_SAFE_VERDICTS.has(verdict),
|
|
44
53
|
faces: row.faces,
|
|
45
54
|
evidenceId: row.evidenceId,
|
|
55
|
+
...(glyphExceptions && glyphExceptions.length > 0
|
|
56
|
+
? { glyphExceptions }
|
|
57
|
+
: {}),
|
|
46
58
|
};
|
|
47
59
|
}
|
|
48
60
|
/** Decide a single row against the consumer's asset availability. Pure. */
|
|
@@ -98,7 +110,7 @@ function decideRowForFace(row, face, canRenderFamily) {
|
|
|
98
110
|
const faceVerdict = row.faceVerdicts?.[face] ?? row.verdict;
|
|
99
111
|
return {
|
|
100
112
|
kind: "fallback",
|
|
101
|
-
fallback: buildFallback(row, base.fallback.substituteFamily, faceVerdict),
|
|
113
|
+
fallback: buildFallback(row, base.fallback.substituteFamily, faceVerdict, face),
|
|
102
114
|
};
|
|
103
115
|
}
|
|
104
116
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -99,6 +99,14 @@ export interface FontFallback {
|
|
|
99
99
|
faces: FaceCoverage;
|
|
100
100
|
/** stable reviewed-evidence id; look the full row up in {@link SUBSTITUTION_EVIDENCE}. */
|
|
101
101
|
evidenceId: string;
|
|
102
|
+
/**
|
|
103
|
+
* Named glyph-level divergences that qualify this fallback (e.g. one codepoint reflows). Scoped to
|
|
104
|
+
* the lookup: a family lookup ({@link getRenderableFallback}) carries ALL of the row's exceptions; a
|
|
105
|
+
* face lookup ({@link getRenderableFallbackForFace}) carries only the requested face's. Omitted when
|
|
106
|
+
* none apply - so a renderer can surface a precise "this face reflows on U+0060" without re-deriving.
|
|
107
|
+
* A fresh array each call (readonly): mutating it never affects another lookup.
|
|
108
|
+
*/
|
|
109
|
+
glyphExceptions?: readonly GlyphException[];
|
|
102
110
|
}
|
|
103
111
|
/**
|
|
104
112
|
* The full, honest outcome of a fallback lookup. A discriminated union so a consumer can tell apart
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docfonts/fallbacks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Measured open-font fallbacks for proprietary document fonts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"directory": "packages/fallbacks"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
|
+
"gen:data": "bun run scripts/generate-data.ts",
|
|
38
39
|
"build": "tsc -p tsconfig.build.json",
|
|
39
40
|
"prepack": "bun run build"
|
|
40
41
|
},
|