( snapshot: GitSnapshot, id: string, source: GoogleFamilyDirectory, ctx: ReturnType<typeof createFontContext>, matchLanguages: ReturnType<typeof createLanguageMatcher>, )
| 647 | }; |
| 648 | |
| 649 | const inspectFamilySources = async ( |
| 650 | snapshot: GitSnapshot, |
| 651 | id: string, |
| 652 | source: GoogleFamilyDirectory, |
| 653 | ctx: ReturnType<typeof createFontContext>, |
| 654 | matchLanguages: ReturnType<typeof createLanguageMatcher>, |
| 655 | ): Promise<{ |
| 656 | sources: Family['sources']; |
| 657 | languages: string[]; |
| 658 | }> => { |
| 659 | const { directory, family, files } = source; |
| 660 | const sourcePaths = new Set<string>(); |
| 661 | const declaredVariants = new Map<string, GoogleFont>(); |
| 662 | |
| 663 | for (const font of family.fonts) { |
| 664 | if (basename(font.filename) !== font.filename) { |
| 665 | throw new Error(`${id} declares non-root font path ${font.filename}`); |
| 666 | } |
| 667 | const path = `${directory}/${font.filename}`; |
| 668 | if (!files.has(path)) { |
| 669 | throw new Error(`${id} is missing declared source ${path}`); |
| 670 | } |
| 671 | sourcePaths.add(path); |
| 672 | declaredVariants.set(path, font); |
| 673 | } |
| 674 | |
| 675 | for (const path of files) { |
| 676 | if (path.startsWith(`${directory}/static/`) && path.endsWith('.ttf')) { |
| 677 | sourcePaths.add(path); |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | const sources: Family['sources'] = []; |
| 682 | const coverage: FontCoverage[] = []; |
| 683 | |
| 684 | // Keep inspection sequential: a single source face can already be memory-heavy. |
| 685 | for (const path of Array.from(sourcePaths).toSorted(compareStrings)) { |
| 686 | const contents = snapshot.read(path); |
| 687 | const declared = declaredVariants.get(path); |
| 688 | const inspected = await inspectFont(ctx, new Uint8Array(contents)); |
| 689 | sources.push({ |
| 690 | path, |
| 691 | sha256: sha256(contents), |
| 692 | size: contents.byteLength, |
| 693 | variant: declared |
| 694 | ? { weight: declared.weight, style: declared.style } |
| 695 | : undefined, |
| 696 | inspection: normalizeInspection(inspected), |
| 697 | }); |
| 698 | coverage.push(inspected.unicodeRanges); |
| 699 | } |
| 700 | |
| 701 | return { |
| 702 | sources, |
| 703 | languages: |
| 704 | family.languages.length > 0 |
| 705 | ? [...family.languages].toSorted(compareStrings) |
| 706 | : matchLanguages(coverage), |
no test coverage detected