subfont 6.11.0 → 6.12.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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ### v6.12.0 (2022-09-07)
2
+
3
+ - [Refactor repeated code into helper function](https://github.com/Munter/subfont/commit/5335d931957cadc150fed1c5d548ee6b6e245636) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
4
+ - [Clamp the used variation axis values to the available interval](https://github.com/Munter/subfont/commit/1429c0f35720ee8dadb691138eb4cfa3c1c86150) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
5
+ - [Detech unused slnt variation axis ranges](https://github.com/Munter/subfont/commit/dc4be1598ba1ba0e65d8269d0fa2d25aa528357d) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
6
+ - [Report variation axes that only use the default value as unused rather than underutilized](https://github.com/Munter/subfont/commit/12082590898407f558d9540347778272ddb9d197) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
7
+ - [Detect unused wdth variation axis ranges](https://github.com/Munter/subfont/commit/d7758eb3c9a45a49768aac12c36ed897a0c4b467) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
8
+
1
9
  ### v6.11.0 (2022-09-04)
2
10
 
3
11
  - [Treat wdth as a standard axis \(but unsupported for now\)](https://github.com/Munter/subfont/commit/20d539750448134cca0a82f2cc98f85d9a6be068) ([Andreas Lind](mailto:andreaslindpetersen@gmail.com))
@@ -1,6 +1,7 @@
1
1
  const cssFontWeightNames = require('css-font-weight-names');
2
2
  const initialValueByProp = require('./initialValueByProp');
3
3
  const unquote = require('./unquote');
4
+ const normalizeFontStretch = require('font-snapper/lib/normalizeFontStretch');
4
5
 
5
6
  function normalizeFontPropertyValue(propName, value) {
6
7
  const propNameLowerCase = propName.toLowerCase();
@@ -22,6 +23,8 @@ function normalizeFontPropertyValue(propName, value) {
22
23
  } else {
23
24
  return value;
24
25
  }
26
+ } else if (propNameLowerCase === 'font-stretch') {
27
+ return normalizeFontStretch(value);
25
28
  } else if (typeof value === 'string' && propNameLowerCase !== 'src') {
26
29
  return value.toLowerCase();
27
30
  }
@@ -213,6 +213,10 @@ function groupTextsByFontFamilyProps(
213
213
  fontVariationSettings: textAndProps.props['font-variation-settings'],
214
214
  fontStyle,
215
215
  fontWeight,
216
+ fontStretch: normalizeFontPropertyValue(
217
+ 'font-stretch',
218
+ textAndProps.props['font-stretch']
219
+ ),
216
220
  animationTimingFunction:
217
221
  textAndProps.props['animation-timing-function'],
218
222
  props,
@@ -234,6 +238,9 @@ function groupTextsByFontFamilyProps(
234
238
  );
235
239
  const fontStyles = new Set(textsPropsArray.map((obj) => obj.fontStyle));
236
240
  const fontWeights = new Set(textsPropsArray.map((obj) => obj.fontWeight));
241
+ const fontStretches = new Set(
242
+ textsPropsArray.map((obj) => obj.fontStretch)
243
+ );
237
244
  const fontVariationSettings = new Set(
238
245
  textsPropsArray
239
246
  .map((obj) => obj.fontVariationSettings)
@@ -274,6 +281,7 @@ function groupTextsByFontFamilyProps(
274
281
  fontUrl,
275
282
  fontFamilies,
276
283
  fontStyles,
284
+ fontStretches,
277
285
  fontWeights,
278
286
  fontVariationSettings,
279
287
  hasOutOfBoundsAnimationTimingFunction,
@@ -638,6 +646,9 @@ function cssAssetIsEmpty(cssAsset) {
638
646
  }
639
647
 
640
648
  function parseFontWeightRange(str) {
649
+ if (typeof str === 'undefined' || str === 'auto') {
650
+ return [-Infinity, Infinity];
651
+ }
641
652
  let minFontWeight = 400;
642
653
  let maxFontWeight = 400;
643
654
  const fontWeightTokens = str.split(/\s+/).map((str) => parseFloat(str));
@@ -653,6 +664,27 @@ function parseFontWeightRange(str) {
653
664
  return [minFontWeight, maxFontWeight];
654
665
  }
655
666
 
667
+ function parseFontStretchRange(str) {
668
+ if (typeof str === 'undefined' || str.toLowerCase() === 'auto') {
669
+ return [-Infinity, Infinity];
670
+ }
671
+ let minFontStretch = 100;
672
+ let maxFontStretch = 100;
673
+ const fontStretchTokens = str
674
+ .split(/\s+/)
675
+ .map((str) => normalizeFontPropertyValue('font-stretch', str));
676
+ if (
677
+ [1, 2].includes(fontStretchTokens.length) &&
678
+ !fontStretchTokens.some(isNaN)
679
+ ) {
680
+ minFontStretch = maxFontStretch = fontStretchTokens[0];
681
+ if (fontStretchTokens.length === 2) {
682
+ maxFontStretch = fontStretchTokens[1];
683
+ }
684
+ }
685
+ return [minFontStretch, maxFontStretch];
686
+ }
687
+
656
688
  function warnAboutMissingGlyphs(htmlOrSvgAssetTextsWithProps, assetGraph) {
657
689
  const missingGlyphsErrors = [];
658
690
 
@@ -744,8 +776,9 @@ These glyphs are used on your site, but they don't exist in the font you applied
744
776
  }
745
777
 
746
778
  const standardVariationAxes = new Set(['wght', 'wdth', 'ital', 'slnt', 'opsz']);
747
- // Tracing the ranges of these standard axes require a bit more work, so just skip them for now:
748
- const ignoredVariationAxes = new Set(['wdth', 'slnt', 'opsz']);
779
+ // It would be very hard to trace statically which values of opsz (font-optical-sizing)
780
+ // are going to be used, so we ignore that one:
781
+ const ignoredVariationAxes = new Set(['opsz']);
749
782
 
750
783
  function renderNumberRange(min, max) {
751
784
  if (min === max) {
@@ -762,60 +795,72 @@ function warnAboutUnusedVariationAxes(
762
795
  const seenAxisValuesByFontUrlAndAxisName = new Map();
763
796
  const outOfBoundsAxesByFontUrl = new Map();
764
797
 
798
+ function noteUsedValue(fontUrl, axisName, axisValue) {
799
+ let seenAxes = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
800
+ if (!seenAxes) {
801
+ seenAxes = new Map();
802
+ seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
803
+ }
804
+ if (seenAxes.has(axisName)) {
805
+ seenAxes.get(axisName).push(axisValue);
806
+ } else {
807
+ seenAxes.set(axisName, [axisValue]);
808
+ }
809
+ }
810
+
765
811
  for (const { fontUsages } of htmlOrSvgAssetTextsWithProps) {
766
812
  for (const {
767
813
  fontUrl,
768
- fontVariationSettings,
769
814
  fontStyles,
770
815
  fontWeights,
816
+ fontStretches,
817
+ fontVariationSettings,
771
818
  hasOutOfBoundsAnimationTimingFunction,
772
819
  props,
773
820
  } of fontUsages) {
774
- let seenAxes = seenAxisValuesByFontUrlAndAxisName.get(fontUrl);
775
- if (!seenAxes) {
776
- seenAxes = new Map();
777
- seenAxisValuesByFontUrlAndAxisName.set(fontUrl, seenAxes);
778
- }
779
- const seenItalValues = [];
780
821
  if (fontStyles.has('italic')) {
781
- seenItalValues.push(1);
822
+ noteUsedValue(fontUrl, 'ital', 1);
782
823
  }
783
824
  // If any font-style value except italic is seen (including normal or oblique)
784
825
  // we're also utilizing value 0:
785
826
  if (fontStyles.size > fontStyles.has('italic') ? 1 : 0) {
786
- seenItalValues.push(0);
827
+ noteUsedValue(fontUrl, 'ital', 0);
787
828
  }
788
- if (seenItalValues.length > 0) {
789
- if (seenAxes.has('ital')) {
790
- seenAxes.get('ital').push(...seenItalValues);
791
- } else {
792
- seenAxes.set('ital', seenItalValues);
793
- }
829
+ if (fontStyles.has('oblique')) {
830
+ // https://www.w3.org/TR/css-fonts-4/#font-style-prop
831
+ // oblique <angle>?
832
+ // [...] The lack of an <angle> represents 14deg.
833
+ noteUsedValue(fontUrl, 'slnt', 14);
834
+ }
835
+ // If any font-style value except oblique is seen (including normal or italic)
836
+ // we're also utilizing value 0:
837
+ if (fontStyles.size > fontStyles.has('oblique') ? 1 : 0) {
838
+ noteUsedValue(fontUrl, 'slnt', 0);
794
839
  }
795
840
 
796
841
  const minMaxFontWeight = parseFontWeightRange(props['font-weight']);
797
- const seenFontWeightValues = [];
798
842
  for (const fontWeight of fontWeights) {
799
- seenFontWeightValues.push(_.clamp(fontWeight, ...minMaxFontWeight));
843
+ noteUsedValue(
844
+ fontUrl,
845
+ 'wght',
846
+ _.clamp(fontWeight, ...minMaxFontWeight)
847
+ );
800
848
  }
801
- if (seenFontWeightValues.length > 0) {
802
- if (seenAxes.has('wght')) {
803
- seenAxes.get('wght').push(...seenFontWeightValues);
804
- } else {
805
- seenAxes.set('wght', seenFontWeightValues);
806
- }
849
+
850
+ const minMaxFontStretch = parseFontStretchRange(props['font-stretch']);
851
+ for (const fontStrech of fontStretches) {
852
+ noteUsedValue(
853
+ fontUrl,
854
+ 'wdth',
855
+ _.clamp(fontStrech, ...minMaxFontStretch)
856
+ );
807
857
  }
808
858
 
809
859
  for (const fontVariationSettingsValue of fontVariationSettings) {
810
860
  for (const [axisName, axisValue] of parseFontVariationSettings(
811
861
  fontVariationSettingsValue
812
862
  )) {
813
- const seenAxisValues = seenAxes.get(axisName);
814
- if (seenAxisValues) {
815
- seenAxisValues.push(axisValue);
816
- } else {
817
- seenAxes.set(axisName, [axisValue]);
818
- }
863
+ noteUsedValue(fontUrl, axisName, axisValue);
819
864
  if (hasOutOfBoundsAnimationTimingFunction) {
820
865
  let outOfBoundsAxes = outOfBoundsAxesByFontUrl.get(fontUrl);
821
866
  if (!outOfBoundsAxes) {
@@ -850,8 +895,13 @@ function warnAboutUnusedVariationAxes(
850
895
  if (ignoredVariationAxes.has(name)) {
851
896
  continue;
852
897
  }
898
+ let usedValues = [];
853
899
  if (seenAxisValuesByAxisName.has(name) && !outOfBoundsAxes.has(name)) {
854
- const usedValues = [...seenAxisValuesByAxisName.get(name)];
900
+ usedValues = [...seenAxisValuesByAxisName.get(name)].map((usedValue) =>
901
+ _.clamp(usedValue, min, max)
902
+ );
903
+ }
904
+ if (!usedValues.every((value) => value === defaultValue)) {
855
905
  if (!standardVariationAxes.has(name)) {
856
906
  usedValues.push(defaultValue);
857
907
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subfont",
3
- "version": "6.11.0",
3
+ "version": "6.12.0",
4
4
  "description": "Speeds up your pages initial paint by automatically subsetting local or Google fonts and loading them optimally",
5
5
  "engines": {
6
6
  "node": ">=10.0.0"