diff --git a/font-src/derive-spacing.mjs b/font-src/derive-spacing.mjs new file mode 100644 index 000000000..19be992f6 --- /dev/null +++ b/font-src/derive-spacing.mjs @@ -0,0 +1,80 @@ +import fs from "fs"; + +import { FontIo, Ot } from "ot-builder"; + +import { assignFontNames, createNamingDictFromArgv } from "./gen/meta/naming.mjs"; + +export default main; + +async function main(argv) { + const font = await readTTF(argv); + + const naming = createNamingDictFromArgv(argv); + assignFontNames(font, naming, false); + + switch (argv.shape.spacing) { + case "term": + deriveTerm(font); + break; + case "fixed": + deriveTerm(font); + deriveFixed(font); + break; + } + + await saveTTF(argv, font); +} + +// To derive -Term variants, simply apply NWID +function deriveTerm(font) { + const gsub = font.gsub; + let nwidMap = new Map(); + for (const feature of gsub.features) { + if (feature.tag !== "NWID") continue; + for (const lookup of feature.lookups) { + if (!(lookup instanceof Ot.Gsub.Single)) continue; + for (const [from, to] of lookup.mapping) { + nwidMap.set(from, to); + } + } + } + + for (const [ch, g] of [...font.cmap.unicode.entries()]) { + const narrow = nwidMap.get(g); + if (narrow) font.cmap.unicode.set(ch, narrow); + } + for (const [ch, vs, g] of [...font.cmap.vs.entries()]) { + const narrow = nwidMap.get(g); + if (narrow) font.cmap.vs.set(ch, vs, narrow); + } +} + +// In FontConfig, a font is considered "monospace" if and only if all encoded non-combining +// characters (AW > 0) have the same width. We use this method to validate whether our +// "Fixed" subfamilies are properly built. +function deriveFixed(font) { + const unitWidth = font.os2.xAvgCharWidth; + for (const [ch, g] of [...font.cmap.unicode.entries()]) { + const advanceWidth = g.horizontal.end - g.horizontal.start; + if (!(advanceWidth === 0 || advanceWidth === unitWidth)) font.cmap.unicode.delete(ch); + } + for (const [ch, vs, g] of [...font.cmap.vs.entries()]) { + const advanceWidth = g.horizontal.end - g.horizontal.start; + if (!(advanceWidth === 0 || advanceWidth === unitWidth)) font.cmap.vs.delete(ch, vs); + } +} + +async function readTTF(argv) { + const buf = await fs.promises.readFile(argv.i); + const sfnt = FontIo.readSfntOtf(buf); + const font = FontIo.readFont(sfnt, Ot.ListGlyphStoreFactory); + return font; +} +async function saveTTF(argv, font) { + const sfnt = FontIo.writeFont(font, { + glyphStore: { statOs2XAvgCharWidth: false }, + generateDummyDigitalSignature: true + }); + const buf = FontIo.writeSfntOtf(sfnt); + await fs.promises.writeFile(argv.o, buf); +} diff --git a/font-src/gen/build-font.mjs b/font-src/gen/build-font.mjs index 3778e9d8e..7771ea7f3 100644 --- a/font-src/gen/build-font.mjs +++ b/font-src/gen/build-font.mjs @@ -1,20 +1,22 @@ import { buildGlyphs } from "../glyphs/index.mjs"; import { copyFontMetrics } from "../meta/aesthetics.mjs"; -import { assignFontNames } from "../meta/naming.mjs"; import { buildOtl } from "../otl/index.mjs"; import * as Caching from "./caching/index.mjs"; -import { CreateEmptyFont } from "./empty-font.mjs"; import { finalizeFont } from "./finalize/index.mjs"; +import { CreateEmptyFont } from "./meta/empty-font.mjs"; +import { assignFontNames } from "./meta/naming.mjs"; import { convertOtd } from "./otd-conv/index.mjs"; -("use strict"); export async function buildFont(argv, para) { - const gs = buildGlyphs(para); const baseFont = CreateEmptyFont(argv); - assignFontNames(para, baseFont); + assignFontNames(baseFont, para.naming, para.isQuasiProportional); + + const gs = buildGlyphs(para); copyFontMetrics(gs.fontMetrics, baseFont); + const otl = buildOtl(para, gs.glyphStore); + // Regulate const excludeChars = new Set(); if (para.excludedCharRanges) { diff --git a/font-src/gen/finalize/index.mjs b/font-src/gen/finalize/index.mjs index af9ad1a92..a105bc508 100644 --- a/font-src/gen/finalize/index.mjs +++ b/font-src/gen/finalize/index.mjs @@ -15,9 +15,10 @@ function assignSubRank(glyphStore) { let sr = 0; for (const g of glyphStore.glyphs()) g.subRank = sr++; } -// In FontConfig, a font is considered "monospace" if and only if all non-combining characters -// (AW > 0) have the same width. We use this method to validate whether our "Fixed" subfamilies -// are properly built. + +// In FontConfig, a font is considered "monospace" if and only if all encoded non-combining +// characters (AW > 0) have the same width. We use this method to validate whether our +// "Fixed" subfamilies are properly built. function validateMonospace(para, glyphStore) { let awSet = new Set(); for (const [u, g] of glyphStore.encodedEntries()) { diff --git a/font-src/gen/empty-font.mjs b/font-src/gen/meta/empty-font.mjs similarity index 100% rename from font-src/gen/empty-font.mjs rename to font-src/gen/meta/empty-font.mjs diff --git a/font-src/gen/meta/naming.mjs b/font-src/gen/meta/naming.mjs new file mode 100644 index 000000000..d676ea3c2 --- /dev/null +++ b/font-src/gen/meta/naming.mjs @@ -0,0 +1,241 @@ +import { Ot } from "ot-builder"; +import semver from "semver"; + +export function createNamingDictFromArgv(argv) { + return { + family: argv.menu.family, + version: argv.menu.version, + weight: argv.menu.weight - 0, + width: argv.menu.width - 0, + slope: argv.menu.slope + }; +} + +export function assignFontNames(font, naming, isQuasiProportional) { + // Clear existing names + font.name.records.length = 0; + + // Preferred names + const family = naming.family.trim(); + const style = getStyle(naming.weight, naming.width, naming.slope); + + nameFont(font, Ot.Name.NameID.PreferredFamily, family); + nameFont(font, Ot.Name.NameID.PreferredSubfamily, style); + nameFont(font, Ot.Name.NameID.WwsFamily, family); + nameFont(font, Ot.Name.NameID.WwsSubfamily, style); + + // Compat banes + const compat = getStyleLinkedStyles(naming.weight, naming.width, naming.slope); + let compatFamily = family; + if (compat.familySuffix !== " Regular") compatFamily = family + " " + compat.familySuffix; + if (compatFamily.length >= 31) compatFamily = family + " " + compat.familySuffixShort; + + nameFont(font, Ot.Name.NameID.LegacyFamily, compatFamily); + nameFont(font, Ot.Name.NameID.LegacySubfamily, compat.style); + + // Unique and Full name + const uniqueName = `${family} ${style} ${naming.version}`; + const fullName = style !== "Regular" ? `${family} ${style}` : family; + const postscriptName = fullName.replace(/ /g, "-"); + nameFont(font, Ot.Name.NameID.UniqueFontId, uniqueName); + nameFont(font, Ot.Name.NameID.FullFontName, fullName); + nameFont(font, Ot.Name.NameID.PostscriptName, postscriptName); + + // Weight, width and slope numbers + font.os2.usWeightClass = naming.weight; + font.os2.usWidthClass = naming.width; + font.os2.panose.bWeight = 1 + naming.weight / 100; + font.os2.sFamilyClass = 0x809; + + // HEAD and OS/2 flags + const isItalic = naming.slope === "italic"; + const isOblique = naming.slope === "oblique"; + const isBold = naming.weight > 650; + + // prettier-ignore + font.os2.fsSelection = accumulateFlags( + [Ot.Os2.FsSelection.OBLIQUE, isOblique], + [Ot.Os2.FsSelection.BOLD, isBold], + [Ot.Os2.FsSelection.ITALIC, isItalic || isOblique], + [Ot.Os2.FsSelection.REGULAR, !isBold && !isItalic && !isOblique], + [Ot.Os2.FsSelection.USE_TYPO_METRICS, true] + ); + + // prettier-ignore + font.head.macStyle = accumulateFlags( + [Ot.Head.MacStyle.Bold, isBold], + [Ot.Head.MacStyle.Italic, isItalic || isOblique], + [Ot.Head.MacStyle.Condensed, naming.width < 5], + [Ot.Head.MacStyle.Extended, naming.width > 5] + ); + + // Panose + font.os2.panose.bFamilyType = 2; + font.os2.panose.bContrast = 3; + font.os2.panose.bXHeight = 4; + + // Pitch + if (!isQuasiProportional) { + font.os2.panose.bProportion = 9; // Monospaced + font.post.isFixedPitch = true; + } else { + font.os2.panose.bProportion = 0; + font.post.isFixedPitch = false; + } + + // Licensing + if (naming.miscNames) { + nameFont(font, Ot.Name.NameID.Copyright, naming.miscNames.copyright); + nameFont(font, Ot.Name.NameID.Manufacturer, naming.miscNames.manufacturer); + nameFont(font, Ot.Name.NameID.Designer, naming.miscNames.designer); + nameFont(font, Ot.Name.NameID.Description, naming.miscNames.description); + nameFont(font, Ot.Name.NameID.LicenseDescription, naming.miscNames.licence); + } + + // Version + nameFont(font, Ot.Name.NameID.VersionString, `Version ${naming.version}`); + const majorVersion = semver.major(naming.version); + const minorVersion = semver.minor(naming.version); + const patchVersion = semver.patch(naming.version); + if (minorVersion > 99 || patchVersion > 99) throw new RangeError("Version number overflow"); + font.head.fontRevision = majorVersion + (minorVersion * 10 + patchVersion) / 1000; + + // Misc + font.os2.ulCodePageRange1 = 0x2000011f; + font.os2.ulCodePageRange2 = 0xc4000000; + font.head.flags = accumulateFlags( + [Ot.Head.Flags.BaseLineYAt0, true], + [Ot.Head.Flags.LeftSidebearingAtX0, true], + [Ot.Head.Flags.InstructionsMayDependOnPointSize, true], + [Ot.Head.Flags.ForcePpemToBeInteger, true], + [Ot.Head.Flags.InstructionMayAlterAdvanceWidth, true] + ); +} + +function accumulateFlags(...entries) { + let s = 0; + for (const [flag, cond] of entries) { + if (cond) s |= flag; + } + return s; +} + +function getStyleLinkedStyles(weight, width, slope) { + let linkWeight = weight; + let linkSlope = slope; + let nameSuffixWeight = 400; + let nameSuffixWidth = width; + let nameSuffixSlope = "normal"; + + if (!(linkWeight === 400 || linkWeight == 700)) { + nameSuffixWeight = linkWeight; + linkWeight = 400; + } + + if (!(linkSlope === "normal" || linkSlope === "italic")) { + nameSuffixSlope = linkSlope; + linkSlope = "normal"; + } + + return { + style: getStyle(linkWeight, 5, linkSlope), + familySuffix: getStyle(nameSuffixWeight, nameSuffixWidth, nameSuffixSlope), + familySuffixShort: getShortStyle(nameSuffixWeight, nameSuffixWidth, nameSuffixSlope) + }; +} + +function nameFont(font, nameID, str) { + // Mac Roman + font.name.records.push({ + platformID: 1, + encodingID: 0, + languageID: 0, + nameID, + value: Buffer.from(str, "utf-8") + }); + + // Windows Unicode English + font.name.records.push({ + platformID: 3, + encodingID: 1, + languageID: 1033, + nameID, + value: str + }); +} + +function isRBIZ(weight, slope) { + return (weight === 400 || weight === 700) && (slope === "normal" || slope === "italic"); +} + +function getStyle(weight, width, slope) { + const weightPart = weightToMenuStyleMap[weight] ?? "W" + weight; + const widthPart = widthToMenuStyleMap[width] ?? "Wd" + width; + const slopePart = slopeToMenuStyleMap[slope] ?? ""; + const rawName = weightPart + " " + widthPart + " " + slopePart; + return rawName.replace(/ +/g, " ").trim() || "Regular"; +} +function getShortStyle(weight, width, slope) { + const weightPart = weightToMenuStyleMapShort[weight] ?? "W" + weight; + const widthPart = widthToMenuStyleMapShort[width] ?? "Wd" + width; + const slopePart = slopeToMenuStyleMapShort[slope] ?? ""; + const rawName = weightPart + " " + widthPart + " " + slopePart; + return rawName.replace(/ +/g, " ").trim() || "Regular"; +} + +const weightToMenuStyleMap = { + 100: "Thin", + 200: "Extralight", + 300: "Light", + 400: "", + 450: "Book", + 500: "Medium", + 600: "Semibold", + 700: "Bold", + 800: "Extrabold", + 900: "Heavy" +}; +const widthToMenuStyleMap = { + 1: "Ultra-Condensed", + 2: "Extra-Condensed", + 3: "Condensed", + 4: "Semi-Condensed", + 5: "", + 6: "Semi-Extended", + 7: "Extended", + 8: "Extra-Extended", + 9: "Ultra-Extended" +}; +const slopeToMenuStyleMap = { + normal: "", + italic: "Italic", + oblique: "Oblique" +}; +const weightToMenuStyleMapShort = { + 100: "Th", + 200: "XLt", + 300: "Lt", + 400: "", + 450: "Bk", + 500: "Md", + 600: "SmBd", + 700: "Bd", + 800: "XBd", + 900: "Hv" +}; +const widthToMenuStyleMapShort = { + 1: "UltCn", + 2: "XCn", + 3: "Cn", + 4: "SmCn", + 5: "", + 6: "SmEx", + 7: "Ex", + 8: "XEx", + 9: "UltEx" +}; +const slopeToMenuStyleMapShort = { + normal: "", + italic: "It", + oblique: "Obl" +}; diff --git a/font-src/glyphs/symbol/punctuation/percentages.ptl b/font-src/glyphs/symbol/punctuation/percentages.ptl index b18efe274..beed6a78d 100644 --- a/font-src/glyphs/symbol/punctuation/percentages.ptl +++ b/font-src/glyphs/symbol/punctuation/percentages.ptl @@ -9,8 +9,8 @@ glyph-block Symbol-Punctuation-Percentages : begin glyph-block-import CommonShapes glyph-block-import Common-Derivatives - define [NarrowUnicode u] : if (para.spacing < 1) u null - define [WideUnicode u] : if (para.spacing >= 1) u null + define NarrowUnicode : NarrowUnicodeT WideWidth1 + define WideUnicode : WideUnicodeT WideWidth1 define [PercentBarCor df sw] : HVContrast / [Math.sqrt (1 - [Math.pow ((df.rightSB - df.leftSB - sw) / (CAP - 0)) 2])] define [PercentBarShape df sw] : begin @@ -108,9 +108,6 @@ glyph-block Symbol-Punctuation-Percentages : begin create-forked-glyph 'permille.WWID.ringsContinuousSlashAlsoConnected' : composite-proc [ConnnectedBar] [PerMilleProc] create-forked-glyph 'basepoint.WWID.ringsContinuousSlashAlsoConnected' : composite-proc [ConnnectedBar] [BasePointProc] - select-variant 'permille.WWID' [WideUnicode 0x2030] (follow -- 'permille.WWID') - select-variant 'basepoint.WWID' [WideUnicode 0x2031] (follow -- 'permille.WWID') - create-glyph 'percent.ringsSegmentedSlash' : glyph-proc set-width Width local l : SB / 2 @@ -191,4 +188,6 @@ glyph-block Symbol-Punctuation-Percentages : begin select-variant 'percent' '%' select-variant 'permille.NWID' [NarrowUnicode 0x2030] (follow -- 'permille.NWID') + select-variant 'permille.WWID' [WideUnicode 0x2030] (follow -- 'permille.WWID') select-variant 'basepoint.NWID' [NarrowUnicode 0x2031] (follow -- 'permille.NWID') + select-variant 'basepoint.WWID' [WideUnicode 0x2031] (follow -- 'permille.WWID') diff --git a/font-src/index.mjs b/font-src/index.mjs index cdc22ef04..6991193da 100644 --- a/font-src/index.mjs +++ b/font-src/index.mjs @@ -8,6 +8,7 @@ import { encode } from "@msgpack/msgpack"; import { FontIo } from "ot-builder"; import { buildFont } from "./gen/build-font.mjs"; +import { createNamingDictFromArgv } from "./gen/meta/naming.mjs"; import { createGrDisplaySheet } from "./support/gr.mjs"; import { applyLigationData } from "./support/ligation-data.mjs"; import { applyMetricOverride } from "./support/metric-override.mjs"; @@ -44,12 +45,8 @@ async function getParameters() { if (argv.compatibilityLigatures) para.compLig = argv.compatibilityLigatures; if (argv.metricOverride) applyMetricOverride(para, argv.metricOverride, argv); para.naming = { - ...para.naming, - family: argv.menu.family, - version: argv.menu.version, - weight: argv.menu.weight - 0, - width: argv.menu.width - 0, - slope: argv.menu.slope + miscNames: para.naming, + ...createNamingDictFromArgv(argv) }; return para; } diff --git a/font-src/meta/aesthetics.ptl b/font-src/meta/aesthetics.ptl index 7dd72fb72..567cd0730 100644 --- a/font-src/meta/aesthetics.ptl +++ b/font-src/meta/aesthetics.ptl @@ -131,6 +131,9 @@ export : define [calculateMetrics para] : begin define WideWidth3 : if (para.spacing >= 3) WideWidth0 Width define WideWidth4 : if (para.spacing >= 4) WideWidth0 Width + define [NarrowUnicodeT wd] : function [u] : if (wd === Width) u null + define [WideUnicodeT wd] : function [u] : if (wd !== Width) u null + define EssUpper : Stroke * [fallback para.essRatioUpper para.essRatio Contrast] define EssLower : Stroke * [fallback para.essRatioLower para.essRatio Contrast] define EssQuestion : Stroke * [fallback para.essRatioQuestion para.essRatio Contrast] @@ -208,11 +211,12 @@ export : define [calculateMetrics para] : begin AccentClearance AccentHeight CThin CThinB SLAB TailAdjX TailAdjY IBalance IBalance2 JBalance JBalance2 TBalance TBalance2 RBalance RBalance2 FBalance OneBalance WideWidth0 WideWidth1 WideWidth2 WideWidth3 WideWidth4 EssUpper EssLower EssQuestion HalfStroke - RightSB Middle DotRadius PeriodRadius SideJut ArchDepthA ArchDepthB SmallArchDepthA SmallArchDepthB CorrectionOMidX CorrectionOMidS ArchXAdjust compositeBaseAnchors + RightSB Middle DotRadius PeriodRadius SideJut ArchDepthA ArchDepthB SmallArchDepthA + SmallArchDepthB CorrectionOMidX CorrectionOMidS ArchXAdjust compositeBaseAnchors AdviceStroke AdviceStroke2 OverlayStroke OperatorStroke GeometryStroke ShoulderFine _SuperXY adviceSSmooth AdviceGlottalStopArchDepth shoulderMidSlope StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust MidJutSide MidJutCenter YSmoothMidR YSmoothMidL - HSwToV] + HSwToV NarrowUnicodeT WideUnicodeT] export : define [setFontMetrics para metrics fm] : begin define [object CAP Descender XH Width SymbolMid] metrics diff --git a/font-src/meta/macros.ptl b/font-src/meta/macros.ptl index 06bba3c4c..c84553892 100644 --- a/font-src/meta/macros.ptl +++ b/font-src/meta/macros.ptl @@ -222,7 +222,7 @@ define-macro glyph-block : syntax-rules AdviceStroke AdviceStroke2 OverlayStroke OperatorStroke GeometryStroke ShoulderFine _SuperXY adviceSSmooth AdviceGlottalStopArchDepth shoulderMidSlope StrokeWidthBlend ArchDepthAOf ArchDepthBOf SmoothAdjust MidJutSide MidJutCenter compositeBaseAnchors - YSmoothMidR YSmoothMidL HSwToV] + YSmoothMidR YSmoothMidL HSwToV NarrowUnicodeT WideUnicodeT] define spiroFnImports `[g4 g2 corner flat curl close end straight widths disable-contrast heading unimportant important alsoThru alsoThruThem bezControls quadControls archv arcvh dispiro spiro-outline] diff --git a/font-src/meta/naming.ptl b/font-src/meta/naming.ptl deleted file mode 100644 index 5c5fd0e19..000000000 --- a/font-src/meta/naming.ptl +++ /dev/null @@ -1,227 +0,0 @@ -import semver from 'semver' -import [Ot] from "ot-builder" -extern Buffer - -import [fallback] from"../support/utils.mjs" - -define COPYRIGHT 0 -define FAMILY 1 -define STYLE 2 -define UNIQUE_NAME 3 -define FULL_NAME 4 -define VERSION 5 -define POSTSCRIPT 6 -define TRADEMARK 7 -define MANUFACTURER 8 -define DESIGNER 9 -define DESCRIPTION 10 -define LICENCE 13 -define PREFERRED_FAMILY 16 -define PREFERRED_STYLE 17 -define WWS_PREFERRED_FAMILY 21 -define WWS_PREFERRED_STYLE 22 - -define [nameFont font nameid str] : begin - font.name.records.push : object # Mac Roman - platformID 1 - encodingID 0 - languageID 0 - nameID nameid - value : Buffer.from str 'utf-8' - font.name.records.push : object # Windows Unicode English - platformID 3 - encodingID 1 - languageID 1033 - nameID nameid - value str - -define weightToMenuStyleMap : object - 100 "Thin" - 200 "Extralight" - 300 "Light" - 400 "" - 450 "Book" - 500 "Medium" - 600 "Semibold" - 700 "Bold" - 800 "Extrabold" - 900 "Heavy" -define widthToMenuStyleMap : object - 1 "Ultra-Condensed" - 2 "Extra-Condensed" - 3 "Condensed" - 4 "Semi-Condensed" - 5 "" - 6 "Semi-Extended" - 7 "Extended" - 8 "Extra-Extended" - 9 "Ultra-Extended" -define slopeToMenuStyleMap : object - normal "" - italic "Italic" - oblique "Oblique" - -define weightToMenuStyleMapShort : object - 100 "Th" - 200 "XLt" - 300 "Lt" - 400 "" - 450 "Bk" - 500 "Md" - 600 "SmBd" - 700 "Bd" - 800 "XBd" - 900 "Hv" -define widthToMenuStyleMapShort : object - 1 "UltCn" - 2 "XCn" - 3 "Cn" - 4 "SmCn" - 5 "" - 6 "SmEx" - 7 "Ex" - 8 "XEx" - 9 "UltEx" -define slopeToMenuStyleMapShort : object - normal "" - italic "It" - oblique "Obl" - -define [getStyle weight width slope] : begin - define weightPart : fallback weightToMenuStyleMap.(weight) ('W' + weight) - define widthPart : fallback widthToMenuStyleMap.(width) ("Wd" + width) - define slopePart : fallback slopeToMenuStyleMap.(slope) '' - define rawName : weightPart + ' ' + widthPart + ' ' + slopePart - return : [[rawName.replace [regex ' +' 'g'] ' '].trim] || "Regular" - -define [getShortStyle weight width slope] : begin - define weightPart : fallback weightToMenuStyleMapShort.(weight) ('W' + weight) - define widthPart : fallback widthToMenuStyleMapShort.(width) ("Wd" + width) - define slopePart : fallback slopeToMenuStyleMapShort.(slope) '' - define rawName : weightPart + ' ' + widthPart + ' ' + slopePart - return : [rawName.replace [regex ' ' 'g'] ''] || "Regular" - -define [isRBIBI weight slope] : (weight == 400 || weight == 700) && (slope == "normal" || slope == "italic") - -define [getStyleLinkedStyles weight width slope] : begin - local linkWeight weight - local linkSlope slope - local nameSuffixWeight 400 - local nameSuffixWidth width - local nameSuffixSlope "normal" - - # Not regular or bold - if (linkWeight != 400 && linkWeight != 700) : begin - nameSuffixWeight = linkWeight - linkWeight = 400 - - # Not "normal" or italic - if (linkSlope != "normal" && linkSlope != "italic") : begin - nameSuffixSlope = linkSlope - linkSlope = "normal" - - return : list - getStyle linkWeight 5 linkSlope - getStyle nameSuffixWeight nameSuffixWidth nameSuffixSlope - getShortStyle nameSuffixWeight nameSuffixWidth nameSuffixSlope - -define [accumulate entries] : begin - local s 0 - foreach { ev cond } [items-of entries] : begin - if cond : set s : s + ev - return s - -export : define [assignFontNames para font] : begin - # Preferred names - define family : para.naming.family.trim - define style : getStyle para.naming.weight para.naming.width para.naming.slope - define version : "Version " + para.naming.version - - define isItalic : para.naming.slope == "italic" - define isOblique : para.naming.slope == "oblique" - define isBold : para.naming.weight > 650 - - nameFont font PREFERRED_FAMILY family # Preferred Family - nameFont font PREFERRED_STYLE style # Preferred Style - nameFont font WWS_PREFERRED_FAMILY family # WWS Preferred Family - nameFont font WWS_PREFERRED_STYLE style # WWS Preferred Style - - # Compat names - local {compatStyle compatFamilySuffix shortCompatFamilySuffix} : getStyleLinkedStyles para.naming.weight para.naming.width para.naming.slope - local compatFamily family - if (compatFamilySuffix != "Regular") : set compatFamily : family + ' ' + compatFamilySuffix - if (compatFamily.length >= 31) : set compatFamily : family + ' ' + shortCompatFamilySuffix - - nameFont font FAMILY compatFamily # Family - nameFont font STYLE compatStyle # Style - - nameFont font UNIQUE_NAME "\(family) \(style) \(version)" # Unique Name - - local fontfullName : if (style != 'Regular') (family + ' ' + style) family - nameFont font FULL_NAME fontfullName # Full Name - nameFont font POSTSCRIPT : fontfullName.replace [regex ' ' 'g'] '-' # Postscript - - # Misc names - nameFont font COPYRIGHT para.naming.copyright # Copyright - nameFont font MANUFACTURER para.naming.manufacturer # Manufacturer - nameFont font DESIGNER para.naming.designer # Designer - nameFont font DESCRIPTION para.naming.description # Description - nameFont font LICENCE para.naming.licence # Licence - - # Weight, width and slope numbers - set font.os2.usWeightClass para.naming.weight - set font.os2.usWidthClass para.naming.width - set font.os2.panose.bWeight : 1 + para.naming.weight / 100 - set font.os2.sFamilyClass : 8 * 0x100 + 9 - set font.os2.xAvgCharWidth : Math.round para.width - - set font.os2.fsSelection : accumulate : list - list Ot.Os2.FsSelection.OBLIQUE isOblique - list Ot.Os2.FsSelection.BOLD isBold - list Ot.Os2.FsSelection.ITALIC (isItalic || isOblique) - list Ot.Os2.FsSelection.REGULAR (!isBold && !isItalic && !isOblique) - list Ot.Os2.FsSelection.USE_TYPO_METRICS true - set font.head.macStyle : accumulate : list - list Ot.Head.MacStyle.Bold isBold - list Ot.Head.MacStyle.Italic (isItalic || isOblique) - list Ot.Head.MacStyle.Condensed (para.naming.width < 5) - list Ot.Head.MacStyle.Extended (para.naming.width > 5) - - # Version - nameFont font VERSION version # Version - define majorVersion : semver.major para.naming.version - define minorVersion : semver.minor para.naming.version - define patchVersion : semver.patch para.naming.version - if (minorVersion > 99 || patchVersion > 9) : throw : new Error "Version number overflow" - set font.head.fontRevision : majorVersion + (minorVersion * 10 + patchVersion) / 1000 - - # Panose - set font.os2.panose.bFamilyType 2 - set font.os2.panose.bContrast 3 - set font.os2.panose.bXHeight 4 - - # Pitch - if [not para.isQuasiProportional] - : then : begin - set font.os2.panose.bProportion 9 # Monospaced - set font.post.isFixedPitch true - : else : begin - set font.os2.panose.bProportion 0 - set font.post.isFixedPitch false - - # Misc - set font.os2.ulCodePageRange1 0x2000011f - set font.os2.ulCodePageRange2 0xc4000000 - set font.head.flags : accumulate : list - list Ot.Head.Flags.BaseLineYAt0 true - list Ot.Head.Flags.LeftSidebearingAtX0 true - list Ot.Head.Flags.InstructionsMayDependOnPointSize true - list Ot.Head.Flags.ForcePpemToBeInteger true - list Ot.Head.Flags.InstructionMayAlterAdvanceWidth true - - # Enforce the order of NAME table entries - font.name.records.sort : lambda [a b] : begin - if (a.platformID != b.platformID) : return : a.platformID - b.platformID - if (a.encodingID != b.encodingID) : return : a.encodingID - b.encodingID - if (a.languageID != b.languageID) : return : a.languageID - b.languageID - return : a.nameID - b.nameID diff --git a/font-src/otl/index.ptl b/font-src/otl/index.ptl index a52952d39..457114aba 100644 --- a/font-src/otl/index.ptl +++ b/font-src/otl/index.ptl @@ -21,15 +21,14 @@ define GDEF_MARK 3 define [buildGSUB para glyphStore markGlyphs] : begin define gsub : CreateEmptyTable + # NWID / WWID + buildGrFeature gsub glyphStore Gr.Nwid + buildGrFeature gsub glyphStore Gr.Wwid + # lnum / onum buildGrFeature gsub glyphStore Gr.Lnum buildGrFeature gsub glyphStore Gr.Onum - # NWID / WWID - if (!para.forceMonospace || para.spacing > 0) : begin - buildGrFeature gsub glyphStore Gr.Nwid - buildGrFeature gsub glyphStore Gr.Wwid - # APLF buildGrFeature gsub glyphStore Gr.AplForm diff --git a/package-lock.json b/package-lock.json index 06974d41f..7cc2f02de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@iarna/toml": "^2.2.5", "@msgpack/msgpack": "^2.7.2", + "deep-equal": "^2.0.5", "ot-builder": "^1.5.4", "otb-ttc-bundle": "^1.5.4", "semver": "^7.3.7", @@ -789,6 +790,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -821,7 +833,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -964,6 +975,31 @@ } } }, + "node_modules/deep-equal": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", + "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", + "dependencies": { + "call-bind": "^1.0.0", + "es-get-iterator": "^1.1.1", + "get-intrinsic": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.1.1", + "isarray": "^2.0.5", + "object-is": "^1.1.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -974,7 +1010,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -1020,7 +1055,6 @@ "version": "1.20.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -1053,6 +1087,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -1066,7 +1118,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -1782,6 +1833,14 @@ "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -1805,14 +1864,12 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -1836,7 +1893,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1854,7 +1910,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -1868,7 +1923,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -1963,7 +2017,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -1975,7 +2028,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1992,7 +2044,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -2004,7 +2055,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2016,7 +2066,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -2104,7 +2153,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -2114,11 +2162,25 @@ "node": ">= 0.4" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -2130,7 +2192,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -2146,7 +2207,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2170,7 +2230,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -2211,11 +2270,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2236,7 +2302,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -2251,7 +2316,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -2263,11 +2327,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -2279,7 +2350,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -2294,7 +2364,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -2305,11 +2374,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -2317,6 +2411,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2486,7 +2597,21 @@ "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2495,7 +2620,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -2504,7 +2628,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -2853,7 +2976,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -3060,7 +3182,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -3121,7 +3242,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3135,7 +3255,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3296,7 +3415,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -3425,7 +3543,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -3437,6 +3554,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -4233,6 +4383,11 @@ "es-shim-unscopables": "^1.0.0" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4262,7 +4417,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -4373,6 +4527,28 @@ "ms": "2.1.2" } }, + "deep-equal": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", + "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", + "requires": { + "call-bind": "^1.0.0", + "es-get-iterator": "^1.1.1", + "get-intrinsic": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.1.1", + "isarray": "^2.0.5", + "object-is": "^1.1.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.2" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4383,7 +4559,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -4417,7 +4592,6 @@ "version": "1.20.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -4444,6 +4618,21 @@ "unbox-primitive": "^1.0.2" } }, + "es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + } + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -4457,7 +4646,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -5004,6 +5192,14 @@ "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, "fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -5024,14 +5220,12 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -5048,8 +5242,7 @@ "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, "get-caller-file": { "version": "2.0.5", @@ -5061,7 +5254,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -5072,7 +5264,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -5140,7 +5331,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -5148,8 +5338,7 @@ "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" }, "has-flag": { "version": "4.0.0", @@ -5160,7 +5349,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, "requires": { "get-intrinsic": "^1.1.1" } @@ -5168,14 +5356,12 @@ "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -5239,18 +5425,25 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", "side-channel": "^1.0.4" } }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "requires": { "has-bigints": "^1.0.1" } @@ -5259,7 +5452,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -5268,8 +5460,7 @@ "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-core-module": { "version": "2.10.0", @@ -5284,7 +5475,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -5310,11 +5500,15 @@ "is-extglob": "^2.1.1" } }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" }, "is-number": { "version": "7.0.0", @@ -5326,7 +5520,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -5335,17 +5528,20 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -5354,7 +5550,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -5363,20 +5558,49 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", + "has-tostringtag": "^1.0.0" + } + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, "requires": { "call-bind": "^1.0.2" } }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5516,20 +5740,26 @@ "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -5770,7 +6000,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -5907,7 +6136,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -5956,7 +6184,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -5967,7 +6194,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -6086,7 +6312,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -6186,7 +6411,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -6195,6 +6419,30 @@ "is-symbol": "^1.0.3" } }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.9" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 520100e28..f8e836eba 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "toposort": "^2.0.2", "typo-geom": "^0.12.1", "uuid": "^8.3.2", - "wawoff2": "^2.0.1" + "wawoff2": "^2.0.1", + "deep-equal": "^2.0.5" }, "devDependencies": { "@unicode/unicode-14.0.0": "^1.3.0", @@ -33,4 +34,4 @@ "engines": { "node": ">=16.0.0" } -} +} \ No newline at end of file diff --git a/verdafile.mjs b/verdafile.mjs index e947621ce..71069c0e8 100644 --- a/verdafile.mjs +++ b/verdafile.mjs @@ -2,6 +2,7 @@ import * as FS from "fs"; import * as Path from "path"; import * as toml from "@iarna/toml"; +import deepEqual from "deep-equal"; import semver from "semver"; import * as uuid from "uuid"; import * as Verda from "verda"; @@ -148,9 +149,37 @@ const BuildPlans = computed("metadata:build-plans", async target => { } returnBuildPlans[prefix] = bp; } + linkSpacingDerivableBuildPlans(returnBuildPlans); return { fileNameToBpMap, buildPlans: returnBuildPlans }; }); +function linkSpacingDerivableBuildPlans(bps) { + for (const pfxTo in bps) { + const planTo = bps[pfxTo]; + const planToVal = rectifyPlanForSpacingDerivation(planTo); + if (!(planTo.spacing === "term" || planTo.spacing === "fixed")) continue; + for (const pfxFrom in bps) { + const planFrom = bps[pfxFrom]; + if (!(planFrom.spacing === "normal" || !planFrom.spacing)) continue; + const planFromVal = rectifyPlanForSpacingDerivation(planFrom); + if (!deepEqual(planToVal, planFromVal)) continue; + planTo.spacingDeriveFrom = pfxFrom; + } + } +} + +function rectifyPlanForSpacingDerivation(p) { + return { + ...p, + family: "#Validation", + desc: "#Validation", + spacing: "#Validation", + snapshotFamily: null, + snapshotFeature: null, + targets: null + }; +} + const BuildPlanOf = computed.group("metadata:build-plan-of", async (target, gid) => { const [{ buildPlans }] = await target.need(BuildPlans); const plan = buildPlans[gid]; @@ -189,6 +218,15 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa const sfi = sfm[fi0.suffix]; const hintReferenceSuffix = fetchHintReferenceSuffix(sfm); + let spacingDerive = null; + if (bp.spacingDeriveFrom) { + spacingDerive = { + manner: bp.spacing, + prefix: bp.spacingDeriveFrom, + fileName: makeFileName(bp.spacingDeriveFrom, fi0.suffix) + }; + } + return { name: fileName, variants: bp.variants || null, @@ -230,7 +268,10 @@ const FontInfoOf = computed.group("metadata:font-info-of", async (target, fileNa : null, compatibilityLigatures: bp["compatibility-ligatures"] || null, metricOverride: bp["metric-override"] || null, - excludedCharRanges: bp["exclude-chars"]?.ranges + excludedCharRanges: bp["exclude-chars"]?.ranges, + + // Spacing derivation -- creating faster build for spacing variants + spacingDerive }; }); @@ -321,41 +362,59 @@ const ageKey = uuid.v4(); const DistUnhintedTTF = file.make( (gr, fn) => `${DIST}/${gr}/ttf-unhinted/${fn}.ttf`, async (target, out, gr, fn) => { - await target.need(Scripts, Parameters, Dependencies, de(`${BUILD}/caches`)); - const [compositesFromBuildPlan] = await target.need(CompositesFromBuildPlan); - const charMapDir = `${BUILD}/ttf/${gr}`; - const charMapPath = `${charMapDir}/${fn}.charmap.mpz`; + await target.need(Scripts, Parameters, Dependencies); + const [fi] = await target.need(FontInfoOf(fn), de(out.dir)); - const [fi] = await target.need(FontInfoOf(fn), de(out.dir), de(charMapDir)); - const cacheFileName = - `${Math.round(1000 * fi.shape.weight)}-${Math.round(1000 * fi.shape.width)}-` + - `${Math.round(3600 * fi.shape.slopeAngle)}-${fi.shape.slope}`; - const cachePath = `${BUILD}/caches/${cacheFileName}.mpz`; - const cacheDiffPath = `${charMapDir}/${fn}.cache.mpz`; - - echo.action(echo.hl.command(`Create TTF`), fn, echo.hl.operator("->"), out.full); - const { cacheUpdated } = await silently.node("font-src/index.mjs", { - o: out.full, - oCharMap: charMapPath, - cacheFreshAgeKey: ageKey, - iCache: cachePath, - oCache: cacheDiffPath, - compositesFromBuildPlan, - ...fi - }); - if (cacheUpdated) { - const lock = build.locks.alloc(cacheFileName); - await lock.acquire(); - await silently.node(`font-src/merge-cache.mjs`, { - base: cachePath, - diff: cacheDiffPath, - version: fi.menu.version, - freshAgeKey: ageKey + if (fi.spacingDerive) { + // The font is a spacing variant, and is derivable form an existing + // normally-spaced variant. + const spD = fi.spacingDerive; + const [deriveFrom] = await target.need(DistUnhintedTTF(spD.prefix, spD.fileName)); + await silently.node(`font-src/derive-spacing.mjs`, { + i: deriveFrom.full, + o: out.full, + ...fi }); - lock.release(); + } else { + // Ab-initio build + const charMapDir = `${BUILD}/ttf/${gr}`; + const charMapPath = `${charMapDir}/${fn}.charmap.mpz`; + await target.need(de(charMapDir)); + + await target.need(de(`${BUILD}/caches`)); + const cacheFileName = + `${Math.round(1000 * fi.shape.weight)}-${Math.round(1000 * fi.shape.width)}-` + + `${Math.round(3600 * fi.shape.slopeAngle)}-${fi.shape.slope}`; + const cachePath = `${BUILD}/caches/${cacheFileName}.mpz`; + const cacheDiffPath = `${charMapDir}/${fn}.cache.mpz`; + + echo.action(echo.hl.command(`Create TTF`), fn, echo.hl.operator("->"), out.full); + + const [compositesFromBuildPlan] = await target.need(CompositesFromBuildPlan); + const { cacheUpdated } = await silently.node("font-src/index.mjs", { + o: out.full, + oCharMap: charMapPath, + cacheFreshAgeKey: ageKey, + iCache: cachePath, + oCache: cacheDiffPath, + compositesFromBuildPlan, + ...fi + }); + if (cacheUpdated) { + const lock = build.locks.alloc(cacheFileName); + await lock.acquire(); + await silently.node(`font-src/merge-cache.mjs`, { + base: cachePath, + diff: cacheDiffPath, + version: fi.menu.version, + freshAgeKey: ageKey + }); + lock.release(); + } } } ); + const BuildCM = file.make( (gr, f) => `${BUILD}/ttf/${gr}/${f}.charmap.mpz`, async (target, output, gr, f) => { @@ -363,20 +422,19 @@ const BuildCM = file.make( } ); -function formatSuffix(fmt, unhinted) { - return fmt + (unhinted ? "-unhinted" : ""); -} - const DistHintedTTF = file.make( (gr, fn) => `${DIST}/${gr}/ttf/${fn}.ttf`, async (target, out, gr, fn) => { - const [{ hintParams }, hint] = await target.need(FontInfoOf(fn), CheckTtfAutoHintExists); + const [fi, hint] = await target.need(FontInfoOf(fn), CheckTtfAutoHintExists); const [from] = await target.need(DistUnhintedTTF(gr, fn), de`${out.dir}`); echo.action(echo.hl.command(`Hint TTF`), from.full, echo.hl.operator("->"), out.full); - await silently.run(hint, hintParams, from.full, out.full); + await silently.run(hint, fi.hintParams, from.full, out.full); } ); +function formatSuffix(fmt, unhinted) { + return fmt + (unhinted ? "-unhinted" : ""); +} const DistWoff2 = file.make( (gr, fn, unhinted) => `${DIST}/${gr}/${formatSuffix("woff2", unhinted)}/${fn}.woff2`, async (target, out, group, f, unhinted) => {