# Google Font Metadata

[![npm version](https://badge.fury.io/js/google-font-metadata.svg)](https://badge.fury.io/js/google-font-metadata) [![License](https://badgen.net/badge/license/MIT/green)](https://github.com/fontsource/google-font-metadata/blob/master/LICENSE) [![GitHub stars](https://img.shields.io/github/stars/fontsource/google-font-metadata.svg?style=social&label=Star)](https://github.com/fontsource/google-font-metadata/stargazers)

A metadata generator that fetches and parses the Google Fonts API to be primarily used for the [Fontsource monorepo](https://github.com/fontsource/fontsource).

## Installation

Install the package from `npm`:

```shell
npm install google-font-metadata
```

## Usage

The project exports the following data:

```ts
import {
    APIv1,
    APIv2,
    APIVariable,
    APIIconStatic,
    APIIconVariable,
    APILicense,
    APIRegistry,
} from "google-font-metadata";
const {
    APIv1,
    APIv2,
    APIVariable,
    APIIconStatic,
    APIIconVariable,
    APILicense,
    APIRegistry,
} = require("google-font-metadata");

console.dir(APIv2);
```

## APIv1

Uses the Google Fonts CSS APIv1 that includes different font files for each subset, but does NOT include unicode-range values. This isn't usually recommended.

It exports [`data/google-fonts-v1.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/google-fonts-v1.json).

```json
{
...
"abel": {
    "family": "Abel",
    "id": "abel",
    "subsets": ["latin"],
    "weights": [400],
    "styles": ["normal"],
    "variants": {
      "400": {
        "normal": {
          "latin": {
            "url": {
              "woff2": "https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE2V9BPQ.woff2",
              "woff": "https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE2V9BOw.woff",
              "truetype": "https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE2V9BOA.ttf"
            }
          }
        }
      }
    },
    "defSubset": "latin",
    "lastModified": "2022-04-20",
    "version": "v18",
    "category": "sans-serif"
  },
...
}
```

## APIv2

Uses the Google Fonts CSS APIv2 and includes the unicode-range values for every subset. However, the API serves `ttf` files with **ALL** subsets included in one file and therefore all links for those file types in the same subset lead to the same link for each weight and style. `woff2` and `woff` files are individually split per subset.

Exports [`data/google-fonts-v2.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/google-fonts-v2.json).

```json
{
...
"abel": {
    "family": "Abel",
    "id": "abel",
    "subsets": ["latin"],
    "weights": [400],
    "styles": ["normal"],
    "unicodeRange": {
      "latin": "U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD"
    },
    "variants": {
      "400": {
        "normal": {
          "latin": {
            "url": {
              "woff2": "https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE2V9BPQ.woff2",
              "woff": "https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE6Vs.woff",
              "truetype": "https://fonts.gstatic.com/s/abel/v18/MwQ5bhbm2POE6Vg.ttf"
            }
          }
        }
      }
    },
    "defSubset": "latin",
    "lastModified": "2022-04-20",
    "version": "v18",
    "category": "sans-serif"
  },
...
}
```

Note that fonts with large glyphsets such as the Japanese, Korean or Chinese language, are divided into many smaller **numbered** subsets that utilize the unicode-range @fontface selector. An example is Noto Sans JP which returns the following:

```json
{
...
 "noto-sans-jp": {
    "family": "Noto Sans JP",
    "id": "noto-sans-jp",
    "subsets": ["japanese", "latin"],
    "weights": [100, 300, 400, 500, 700, 900],
    "styles": ["normal"],
    "unicodeRange": {
      "[0]": "U+25ee8,...,U+2f9f4",
      "[1]": "U+1f235-1f23b,...,U+25ed8",
      ...
      "[119]": "U+20,...,U+ff0e"
      },
    "variants": {
      "100": {
        "normal": {
          "[0]": {
            "url": {
              "woff2": "https://fonts.gstatic.com/s/notosansjp/v42/-F6ofjtqLzI2JPCgQBnw7HFQoggPkENvl4B0ZLgOquiXidBa3qHiDcp2RQ.0.woff2",
              "woff": "https://fonts.gstatic.com/s/notosansjp/v42/-F62fjtqLzI2JPCgQBnw7HFoxQII2lcnk-AFfrgQrvWXpdFg3KXxAMsKMbdN.0.woff",
              "opentype": "https://fonts.gstatic.com/s/notosansjp/v42/-F6ofjtqLzI2JPCgQBnw7HFQoggM.otf"
            }
          },
          ...,
        },
        ...,
      }
    }
  }
...
}
```

## APIVariable

Scrapes the Google Fonts directory and uses the Google Fonts API to generate all the relevant axis definitions and download variant metadata. You can learn more variable font axis' [here](https://fonts.google.com/variablefonts).

There are 3 default variants:

-   `wght` - Only links to font files that only have the `wght` axis.
-   `standard` - A default set of fonts that includes `wght, wdth, slnt, opsz` axis' if available.
-   `full` - Links to font files that have all the axis' included within them.

Furthermore, a variant is generated for each unique axis in the font, e.g. if `wdth` exists, `variants.wdth.normal.latin` will exist. Note that the `wght` axis is also included in each unique custom variant.

Note that `standard` or `full` variants may not exist if there are no relevant axes in the font for that classification. This is to prevent duplicate variants with different names.

Exports [`data/variable.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/variable.json).

```json
{
...
"akshar": {
    "family": "Akshar",
    "id": "akshar",
    "axes": {
      "wght": { "default": "400", "min": "300", "max": "700", "step": "1" }
    },
    "variants": {
      "wght": {
        "normal": {
          "devanagari": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCpR5lhOc.woff2",
          "latin-ext": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCqh5lhOc.woff2",
          "latin": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCpB5l.woff2"
        }
      },
      "full": {
        "normal": {
          "devanagari": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCpR5lhOc.woff2",
          "latin-ext": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCqh5lhOc.woff2",
          "latin": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCpB5l.woff2"
        }
      },
      "standard": {
        "normal": {
          "devanagari": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCpR5lhOc.woff2",
          "latin-ext": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCqh5lhOc.woff2",
          "latin": "https://fonts.gstatic.com/s/akshar/v5/Yq6V-LyHWTfz9rGCpB5l.woff2"
        }
      }
    }
  },
...
}
```

Note that certain fonts such as Inter or Recursive have the SLNT axis, meaning their `font-style` in CSS won't be `normal` or `italic` on property `full` but `oblique x deg x deg`. Refer to the [CSS test fixture](https://github.com/fontsource/google-font-metadata/blob/v4/tests/fixtures/variable-parser/recursive-slnt-normal.css) for Recursive. While still showing as `normal` in metadata, it is up to the developer to include the `oblique` style if they are generating CSS using the `min` and `max` values from `recursive.axes.slnt` property.

### APIDirect and APIVariableDirect

These are arrays of generated objects from the `npx gfm generate [key]` command. It is unlikely you will use this.

```ts
import { APIDirect, APIVariableDirect } from "google-font-metadata";
const { APIDirect, APIVariableDirect } = require("google-font-metadata");
```

Exports [`data/api-response.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/api-response.json) and [`data/variable-response.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/variable-response.json) respectively.

## APILicense

Scrapes the [Google Fonts Attribution](https://fonts.google.com/attribution) page and returns a readable object.

```json
{
...
  "abel": {
    "id": "abel",
    "authors": {
      "copyright": "Copyright 2011, Matthew Desmond with Reserved Font Name Abel.",
      "website": "http://www.madtype.com",
      "email": "mattdesmond@gmail.com"
    },
    "license": {
      "type": "SIL Open Font License, 1.1",
      "url": "http://scripts.sil.org/OFL"
    },
    "original": "Copyright (c) 2011, Matthew Desmond (http://www.madtype.com | mattdesmond@gmail.com), with Reserved Font Name Abel."
  },
...
}
```

Exports [`data/licenses.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/licenses.json)

## APIRegistry

```json
{
...
  {
    "name": "Thick Stroke",
    "tag": "XOPQ",
    "min": -1000,
    "max": 2000,
    "default": 88,
    "precision": 0
  },
...
}
```

Exports [`data/axis-registry.json`](https://github.com/fontsource/google-font-metadata/tree/main/data/axis-registry.json)

You can refer to [`src/index.ts`](https://github.com/fontsource/google-font-metadata/blob/main/src/index.ts) and [`src/data.ts`](https://github.com/fontsource/google-font-metadata/blob/main/src/data.ts) to see all exports.

## Updating API Files

You can use the `gfm` CLI tool to update the metadata with fresh results from the Google APIs.

`npx gfm generate [key]` - Fetches the default Google Fonts API which can be used for parsing later. This has to be called before `npx gfm parse`.

Flags:

-   `-n, --normal` - Only fetch the normal Google Developer API for APIv1 and APIv2.
-   `-v, --variable` - Only scrape the variable axis page for APIVariable. Note `key` does not need to be given if this option is passed.

You are able to get a Google Fonts API `key` value from [here](https://console.developers.google.com/apis/credentials). Alternatively, you can use a `.env` file with `API_KEY=keyvalue` instead of providing a key argument in the command.

##

`npx gfm parse` - Parses through the Google Fonts CSS API and generate full metadata using the `generate` command data.

Flags:

-   `-1, --v1` - Only parse and update APIv1.
-   `-2, --v2` - Only parse and update APIv2.
-   `-v, --variable` - Only parse and update APIVariable.
-   `-l, --license` - Only parse and update APILicense.
-   `-f, --force` - This skips the cache and force parses every font.
-   `--no-validate` - This skips invoking `npx gfm validate` after finishing parsing.

##

`npx gfm validate` - Helper command to validate your existing metadata with a schema. This is automatically invoked with `npx gfm parse`.

Flags:

-   `-1, --v1` - Only validate APIv1.
-   `-2, --v2` - Only validate APIv2.
-   `-v, --variable` - Only validate APIVariable.
