Move around files so the repo will be organized as a monorepo.

This commit is contained in:
be5invis 2023-12-03 02:49:33 -08:00
parent 65d1880a84
commit 08c69f0fd3
365 changed files with 1477 additions and 1262 deletions

View file

@ -0,0 +1,5 @@
* `design`, `upright`, `italic`, and `oblique`: Optional, Dictionary, defines styles for individual characters. The choices are organized in key-value pairs, assigning a variant to a character group. Alternatively, you could assign numbers to `cv##` tags, like what you did when using OpenType in CSS. Assignments under `design` will be applied to all the slopes, and `upright`, `italic`, and `oblique` will apply to corresponded slopes.
In addition, style selector for default digit form also uses these dictionaries.
The valid combinations include:

View file

@ -0,0 +1 @@
* `disables` and `enables`: Optional, String Array, Cherry-picking ligation groups to be disabled or enabled. Valid values include:

View file

@ -0,0 +1 @@
* `inherits`: Optional, String, defines the inherited ligation set. When absent, the ligation set will not inherit any other sets. Valid values are:

View file

@ -0,0 +1 @@
* `inherits`: Optional, String, defines the inherited stylistic set. Valid options include:

View file

@ -0,0 +1,18 @@
## Prebuilt Packages
Iosevka provides a large variety of variants. Prebuilt variants are listed below. For all Monospace variants' packages, it will contain three _spacing variants_. You can either download the package containing all the spacing variants (recommended), or cherry-pick the variant with specific spacing.
- _Default_: The default variant with ligatures. Various symbols, like arrows and geometric, are wide (2-column).
- _Terminal_ (“Term”)A narrower variant focusing terminal uses. Arrows and geometric symbols will be narrow to follow typical terminal usages.
- _Fixed_: Exact monospace font without ligatures and wide glyphs. Since some environments cannot interpret Iosevka or Iosevka Term as monospace, and have difficulties with ligatures included, you can use Iosevka Fixed as an alternative.
## Packaging Formats
Iosevka provides various packaging formats, here is the list of them:
| Option | Contents | Description |
| -------------- | --------------------------------------------------- | ------------------------------------------------------------ |
| Super TTC | 1 `.ttc` file | Bundles all fonts in the scope together into a single file. It is the recommended way to install fonts for Desktop usage, if your operating system is updated to date. Package files with `-sgr-` infix in the filename only contains fonts for one single group (variant and spacing). |
| TTC | 9 `.ttc` files | Each TTC file bundles fonts with the same weight together. Package files with `-sgr-` infix in the filename only contains fonts for one single group (variant and spacing). |
| TTF | 54 `.ttf` files | Each TTF file contains one font for a specific weight, width, slope and spacing variant. This option is ideal for embedding Iosevka into applications, or for desktop usage if TTC options have compatibility issues.<br/>TTF packages also provide *unhinted* version which removes [hints](https://en.wikipedia.org/wiki/Font_hinting), which reduced file size, but will be less clear on certain platforms. |
| WebFont | 1 `.css` file + 54 `.woff2` files + 54 `.ttf` files | Contains contents required to use Iosevka on websites. |

View file

@ -0,0 +1,36 @@
import fs from "fs";
import path from "path";
import url from "url";
import semver from "semver";
import { MdCol } from "./md-format-tools.mjs";
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const ChangesFileDir = path.join(__dirname, "../../../changes");
///////////////////////////////////////////////////////////////////////////////////////////////////
// CHANGE LIST
async function GenerateChangeList(argv, out) {
const changeFiles = await fs.promises.readdir(ChangesFileDir);
const fragments = new Map();
for (const file of changeFiles) {
const filePath = path.join(ChangesFileDir, file);
const fileParts = path.parse(filePath);
if (fileParts.ext !== ".md") continue;
if (!semver.valid(fileParts.name) || semver.lt(argv.version, fileParts.name)) continue;
fragments.set(fileParts.name, await fs.promises.readFile(filePath, "utf8"));
}
const sortedFragments = Array.from(fragments).sort((a, b) => semver.compare(b[0], a[0]));
out.log(`## Modifications since last major version`);
for (const [version, notes] of sortedFragments) {
out.log(`\n### ${version}\n`);
out.log(notes.trimEnd() + "\n");
}
}
export default async function main(argv) {
const out = new MdCol();
await GenerateChangeList(argv, out);
await fs.promises.writeFile(argv.outputPath, out.data);
}

View file

@ -0,0 +1,52 @@
import fs from "fs";
import path from "path";
import url from "url";
import SemVer from "semver";
import { MdCol } from "./md-format-tools.mjs";
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
const ChangesFileDir = path.join(__dirname, "../../../changes");
///////////////////////////////////////////////////////////////////////////////////////////////////
// RELEASE NOTE
async function GenerateChangeList(argv, out) {
const changeFiles = await fs.promises.readdir(ChangesFileDir);
const fragments = new Map();
for (const file of changeFiles) {
const filePath = path.join(ChangesFileDir, file);
const fileParts = path.parse(filePath);
if (fileParts.ext !== ".md") continue;
if (!SemVer.valid(fileParts.name) || SemVer.lt(argv.version, fileParts.name)) continue;
fragments.set(fileParts.name, await fs.promises.readFile(filePath, "utf8"));
}
const sortedFragments = Array.from(fragments).sort((a, b) => SemVer.compare(b[0], a[0]));
const latestMajor = SemVer.major(sortedFragments[0][0]);
const latestMinor = SemVer.minor(sortedFragments[0][0]);
for (const [version, notes] of sortedFragments) {
const currentMajor = SemVer.major(version);
const currentMinor = SemVer.minor(version);
if (latestMajor !== currentMajor || latestMinor !== currentMinor) continue;
out.log(``);
out.log(`## Changes of version ${version}`);
out.log(notes.trimEnd() + "\n");
}
}
export default async function main(argv) {
const out = new MdCol("Release-Note");
let baseUrl = `https://github.com/be5invis/Iosevka/blob/v${argv.version}/doc`;
await GenerateChangeList(argv, out);
out.log(
`<table>` +
`<tr><td align="center"><h1>` +
`<a href="${baseUrl}/PACKAGE-LIST.md">View package list</a>` +
`</h1></td></tr>` +
`<tr><td align="center">` +
`<a href="${baseUrl}/packages-sha.txt">Package hashes (SHA-256)</a>` +
`</td></tr>` +
`</table>`
);
await fs.promises.writeFile(argv.outputPath, out.data);
}

View file

@ -0,0 +1,43 @@
import fs from "fs";
import path from "path";
import url from "url";
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
import processCherryPickingStyles from "./sections/cherry-picking-styles.mjs";
import processCvInfluences from "./sections/cv-influences.mjs";
import processCvOt from "./sections/cv-ot.mjs";
import processLangList from "./sections/lang-list.mjs";
import processLigSetCherryPicking from "./sections/lig-set-cherry-picking.mjs";
import processLigSetOt, { isLanguageSpecificLigTag } from "./sections/lig-set-ot.mjs";
import processLigSetPreDef from "./sections/lig-set-pre-def.mjs";
import processPackageList from "./sections/package-list.mjs";
import processPrivateBuildPlans from "./sections/private-build-plans.mjs";
import processSsOt from "./sections/ss-ot.mjs";
import processSsStyles from "./sections/ss-styles.mjs";
export default main;
async function main(argv) {
let readme = await fs.promises.readFile(argv.mdFilePath, "utf-8");
const dirs = {
images: path.posix.relative(path.dirname(argv.mdFilePath), "images"),
fragments: path.resolve(__dirname, "fragments")
};
readme = (await processSsOt(argv, dirs)).apply(readme);
readme = (await processCherryPickingStyles(argv, dirs)).apply(readme);
readme = (await processSsStyles(argv, dirs)).apply(readme);
readme = (await processCvOt(argv, dirs)).apply(readme);
readme = (await processLigSetCherryPicking(argv, dirs)).apply(readme);
readme = (await processLigSetPreDef(argv, dirs)).apply(readme);
readme = (await processLigSetOt(argv, dirs, 1, g => !isLanguageSpecificLigTag(g.tag))).apply(
readme
);
readme = (await processLigSetOt(argv, dirs, 2, g => isLanguageSpecificLigTag(g.tag))).apply(
readme
);
readme = (await processLangList(argv)).apply(readme);
readme = (await processPrivateBuildPlans(argv, dirs)).apply(readme);
readme = (await processCvInfluences(argv)).apply(readme);
readme = (await processPackageList(argv, dirs)).apply(readme);
await fs.promises.writeFile(argv.mdFilePath, readme);
}

View file

@ -0,0 +1,9 @@
import fs from "fs";
export default main;
async function main(argv) {
let readme = await fs.promises.readFile(argv.path, "utf-8");
const currentYear = String(new Date().getFullYear());
readme = readme.replace(/Copyright \(c\) \d{4}-\d{4}/, `Copyright (c) 2015-${currentYear}`);
await fs.promises.writeFile(argv.path, readme);
}

View file

@ -0,0 +1,31 @@
export class MdCol {
constructor(sectionName) {
this.data = "";
this.sectionName = sectionName;
this.matchRegex = new RegExp(
`^([ \\t]*)<!-- BEGIN ${sectionName} -->\\n[\\s\\S]*?<!-- END ${sectionName} -->\\n`,
`m`
);
}
log(...s) {
this.data += s.join("") + "\n";
}
apply(s) {
return s.replace(this.matchRegex, (m, $1) => {
return (
`<!-- BEGIN ${this.sectionName} -->\n` +
`<!-- THIS SECTION IS AUTOMATICALLY GENERATED. DO NOT EDIT. -->\n\n` +
this.data +
`\n<!-- END ${this.sectionName} -->\n`
).replace(/^/gm, $1);
});
}
}
export function ImgX(path, w) {
const widthProp = w ? ` width=${w}` : ``;
return (
`<img src="${path}.light.svg#gh-light-mode-only"${widthProp}/>` +
`<img src="${path}.dark.svg#gh-dark-mode-only"${widthProp}/>`
);
}

View file

@ -0,0 +1,123 @@
import fs from "fs";
import path from "path";
import { parseVariantsData } from "@iosevka/data-export/variants-data";
import { ImgX, MdCol } from "../md-format-tools.mjs";
import { sampleImageCountEmOfCv } from "./cv-ot.mjs";
export default async function processCherryPickingStyles(argv, dirs) {
const variantsData = await parseVariantsData(argv);
const md = new MdCol("Section-Cherry-Picking-Styles");
const headerPath = path.resolve(dirs.fragments, "description-cheery-picking-styles.md");
md.log(await fs.promises.readFile(headerPath, "utf-8"));
for (const cv of [...variantsData.specials, ...variantsData.primes]) {
if (!cv.tag && !cv.isSpecial) continue;
const sampleText = cv.descSampleText
.map(c => (c === "`" ? "`` ` ``" : `\`${c}\``))
.join(", ");
const explainText = cv.samplerExplain ? ` (${cv.samplerExplain})` : ``;
const info = {
introMD: cv.description || `Styles for ${sampleText + explainText}`,
sampleImageCountEm: sampleImageCountEmOfCv(cv),
alternatives: []
};
const defaults = figureOutDefaults(variantsData, cv);
for (const cvv of cv.variants) {
if (!cvv.rank && !cv.isSpecial) continue;
if (cv.tag) {
info.alternatives.push({
imageId: `${cv.key}-${cvv.key}`,
selectors: [`${cv.key} = '${cvv.key}'`, `${cv.tag} = ${cvv.rank}`],
description:
formatDescription(cvv.description) + formatDefaults(cvv.key, defaults)
});
} else {
info.alternatives.push({
imageId: `${cv.key}-${cvv.key}`,
selectors: [`${cv.key} = '${cvv.key}'`],
description:
formatDescription(cvv.description) + formatDefaults(cvv.key, defaults)
});
}
}
formatCv(md, dirs, info);
}
return md;
}
function formatCv(md, dirs, info) {
md.log(` - ${info.introMD}:`);
const imgWidth = 32 * info.sampleImageCountEm;
let sTable = " <table>";
for (const alt of info.alternatives) {
const imageId = `${dirs.images}/cv-${alt.imageId}`;
const image = ImgX(imageId, imgWidth);
const selectorText = alt.selectors.map(x => `<code>${x}</code>`).join(", ");
sTable +=
`<tr><td rowspan="2" width="${2 * 14 + imgWidth}">${image}</td>` +
`<td>${selectorText}</td></tr>`;
sTable += `<tr><td>${alt.description}</td></tr>`;
}
sTable += "</table>";
md.log(sTable);
}
function formatDescription(s) {
return s
.replace(/`` (\S+?) ``/g, ($0, $1) => `<code>${escapeHtml($1)}</code>`)
.replace(/`([^`]+?)`/g, ($0, $1) => `<code>${escapeHtml($1)}</code>`);
}
function escapeHtml(s) {
return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function formatDefaults(selector, defaults) {
let dcs = [],
mask = 0;
for (const dc of defaults) {
if (dc.result !== selector) continue;
dcs.push(dc);
mask |= dc.mask;
}
if (!dcs.length) return "";
if (mask === 0xf) return ` (default)`;
if (mask === 0x5) return ` (default for Upright)`;
if (mask === 0xa) return ` (default for Italic)`;
if (mask === 0x3) return ` (default for Sans)`;
if (mask === 0xc) return ` (default for Slab)`;
return ` (default for ${dcs.map(x => x.desc).join(", ")})`;
}
function figureOutDefaults(variantsData, gr) {
const defaultConfigs = [
{
desc: "Sans Upright",
mask: 1,
result: null,
composition: { ...variantsData.defaults.sans.upright }
},
{
desc: "Sans Italic",
mask: 2,
result: null,
composition: { ...variantsData.defaults.sans.italic }
},
{
desc: "Slab Upright",
mask: 4,
result: null,
composition: { ...variantsData.defaults.slab.upright }
},
{
desc: "Slab Italic",
mask: 8,
result: null,
composition: { ...variantsData.defaults.slab.italic }
}
];
for (const variant of gr.variants) {
for (const dc of defaultConfigs) {
if (variant.key === dc.composition[gr.key]) dc.result = variant.key;
}
}
return defaultConfigs;
}

View file

@ -0,0 +1,83 @@
import { getCharMapAndSupportedLanguageList } from "@iosevka/data-export/supported-languages";
import { MdCol } from "../md-format-tools.mjs";
export default async function processCvInfluences(argv) {
const cl = await getCharMapAndSupportedLanguageList(
argv.charMapPath,
argv.charMapItalicPath,
argv.charMapObliquePath
);
let m = {
upright: new Map(),
italic: new Map()
};
for (const block of cl.unicodeCoverage) {
for (const ch of block.characters) {
if (!ch.inFont) continue;
addToCvInfluenceMap(cl.featureSeries, m.upright, ch.lch, ch.cvFeatureSetsUpright);
addToCvInfluenceMap(cl.featureSeries, m.italic, ch.lch, ch.cvFeatureSetsItalic);
}
}
const md = new MdCol("Section-CV-Influences");
md.log(`### Upright CV influences`);
md.log(``);
logCvInfluenceMap(md, m.upright);
md.log(``);
md.log(`### Italic CV influences`);
md.log(``);
logCvInfluenceMap(md, m.italic);
md.log(``);
return md;
}
function addToCvInfluenceMap(featureSeries, m, lch, ids) {
if (!ids || !ids.length) return;
for (const id of ids) {
let fs = featureSeries[id];
if (!fs) continue;
let s = m.get(fs.name);
if (!s) {
s = new Set();
m.set(fs.name, s);
}
s.add(lch);
}
}
function logCvInfluenceMap(md, m) {
let a = Array.from(m).sort((a, b) => a[0].toUpperCase().localeCompare(b[0].toUpperCase()));
for (const [tag, chars] of a) {
md.log(`- \`${tag}\`:`);
md.log(``);
md.log(` ` + Array.from(chars).map(formatLch).join(", "));
md.log(``);
}
}
function formatLch(lch) {
return mdEscape(lch) + " (`U+" + lch.toString(16).padStart(4, "0").toUpperCase() + "`)";
}
function mdEscape(lch) {
let ch = String.fromCodePoint(lch);
if (ch === "\\") return "\\\\";
if (ch === "`") return "\\`";
if (ch === "*") return "\\*";
if (ch === "_") return "\\_";
if (ch === "{") return "\\{";
if (ch === "}") return "\\}";
if (ch === "[") return "\\[";
if (ch === "]") return "\\]";
if (ch === "(") return "\\(";
if (ch === ")") return "\\)";
if (ch === "#") return "\\#";
if (ch === "+") return "\\+";
if (ch === "-") return "\\-";
if (ch === ".") return "\\.";
if (ch === "!") return "\\!";
return ch;
}

View file

@ -0,0 +1,56 @@
import { parseVariantsData } from "@iosevka/data-export/variants-data";
import { ImgX, MdCol } from "../md-format-tools.mjs";
export default async function processCvOt(argv, dirs) {
const variantsData = await parseVariantsData(argv);
const md = new MdCol("Section-OT-Character-Variants");
const TableColumns = 12;
md.log(`<table>`);
for (const cv of variantsData.primes) {
if (!cv.tag) continue;
let effVariants = [];
for (const cvv of cv.variants) if (cvv.rank) effVariants.push(cvv);
const entryWidth = sampleImageCountEmOfCv(cv);
const imgWidth = 32 * entryWidth;
const entriesPerRow = Math.floor(TableColumns / entryWidth);
const rowsNeeded = Math.ceil(effVariants.length / entriesPerRow);
const itemColSpanHtml = entryWidth > 1 ? ` colspan="${entryWidth}"` : ``;
for (let rid = 0; rid < rowsNeeded; rid++) {
const entriesInThisRow = Math.min(
entriesPerRow,
effVariants.length - rid * entriesPerRow
);
const tailBlankColumnsCount = TableColumns - entryWidth * entriesInThisRow;
// Image row
md.log(`<tr>`);
if (rid === 0) md.log(`<td rowspan="${2 * rowsNeeded}"><code>${cv.tag}</code></td>`);
for (let cid = 0; cid < entriesPerRow; cid++) {
const iCvv = rid * entriesPerRow + cid;
if (iCvv >= effVariants.length) continue;
const cvv = effVariants[iCvv];
const imageID = `${dirs.images}/cv-${cv.key}-${cvv.key}`;
const image = ImgX(imageID, imgWidth);
md.log(`<td${itemColSpanHtml}>${image}</td>`);
}
if (tailBlankColumnsCount > 0) md.log(`<td colspan="${tailBlankColumnsCount}"> </td>`);
md.log(`</tr>`);
// CV ID row
md.log(`<tr>`);
for (let cid = 0; cid < entriesPerRow; cid++) {
const iCvv = rid * entriesPerRow + cid;
if (iCvv >= effVariants.length) continue;
const cvv = effVariants[iCvv];
md.log(`<td${itemColSpanHtml}>${cvv.rank}</td>`);
}
if (tailBlankColumnsCount > 0) md.log(`<td colspan="${tailBlankColumnsCount}"> </td>`);
md.log(`</tr>`);
}
}
md.log(`</table>`);
return md;
}
export function sampleImageCountEmOfCv(cv) {
return cv.hotChars.length * (cv.slopeDependent ? 2 : 1);
}

View file

@ -0,0 +1,15 @@
import { getCharMapAndSupportedLanguageList } from "@iosevka/data-export/supported-languages";
import { MdCol } from "../md-format-tools.mjs";
export default async function processLangList(argv) {
const cl = await getCharMapAndSupportedLanguageList(
argv.charMapPath,
argv.charMapItalicPath,
argv.charMapObliquePath
);
const md = new MdCol("Section-Language-List");
md.log(`${cl.languages.length} Supported Languages: \n`);
md.log(cl.languages.join(", "));
return md;
}

View file

@ -0,0 +1,17 @@
import fs from "fs";
import path from "path";
import { parseLigationData } from "@iosevka/data-export/ligation-data";
import { MdCol } from "../md-format-tools.mjs";
export default async function processLigSetCherryPicking(argv, dirs) {
const ligData = await parseLigationData(argv);
const md = new MdCol("Section-Cherry-Picking-Ligation-Sets");
const headerPath = path.resolve(dirs.fragments, "description-cherry-picking-ligation-sets.md");
md.log(await fs.promises.readFile(headerPath, "utf-8"));
for (const gr in ligData.cherry) {
md.log(` - \`${gr}\`: ${ligData.cherry[gr].desc}.`);
}
return md;
}

View file

@ -0,0 +1,32 @@
import { parseLigationData } from "@iosevka/data-export/ligation-data";
import { ImgX, MdCol } from "../md-format-tools.mjs";
export default async function processLigSetOt(argv, dirs, index, fn) {
const ligData = await parseLigationData(argv);
const md = new MdCol(`Section-OT-Ligation-Tags-${index}`);
md.log(`<table>`);
for (const ls of ligData.sets) {
if (!fn(ls)) continue;
{
md.log(`<tr>`);
if (ls.tagName)
md.log(`<td>${ls.tagName.map(x => `<code>${x}</code>`).join("; ")}</td>`);
else md.log(`<td><code>${ls.tag} off</td>`);
md.log(`<td>${ls.desc}</td>`);
md.log(`</tr>`);
}
{
const imageId = `${dirs.images}/ligset-${ls.tag}-${ls.rank}`;
md.log(`<tr>`);
md.log(`<td colspan="2">${ImgX(imageId)}</td>`);
md.log(`</tr>`);
}
}
md.log(`</table>`);
return md;
}
export function isLanguageSpecificLigTag(tag) {
return tag !== "calt" && tag !== "dlig";
}

View file

@ -0,0 +1,20 @@
import fs from "fs";
import path from "path";
import { parseLigationData } from "@iosevka/data-export/ligation-data";
import { MdCol } from "../md-format-tools.mjs";
export default async function processLigSetPreDef(argv, dirs) {
const ligData = await parseLigationData(argv);
const md = new MdCol("Section-Predefined-Ligation-Sets");
const headerPath = path.resolve(dirs.fragments, "description-predefined-ligation-sets.md");
md.log(await fs.promises.readFile(headerPath, "utf-8"));
for (const gr in ligData.rawSets) {
const readmeDesc =
ligData.rawSets[gr].readmeDesc ||
`Default ligation set would be assigned to ${ligData.rawSets[gr].desc}`;
md.log(` - \`${gr}\`: ${readmeDesc}.`);
}
return md;
}

View file

@ -0,0 +1,105 @@
import fs from "fs";
import path from "path";
import { ImgX, MdCol } from "../md-format-tools.mjs";
const ImagePrefixNoVersion = `https://raw.githubusercontent.com/be5invis/Iosevka`;
const DownloadLinkPrefixNoVersion = `https://github.com/be5invis/Iosevka/releases/download`;
export default async function processPackageList(argv, dirs) {
const imagePrefix = `${ImagePrefixNoVersion}/v${argv.version}/images`;
const pkgShapesData = JSON.parse(await fs.promises.readFile(argv.releasePackagesJsonPath));
const DownloadLinkPrefix = `${DownloadLinkPrefixNoVersion}/v${argv.version}`;
const md = new MdCol("Section-Package-List");
md.log(`# Package list of Release ${argv.version}`);
const headerPath = path.resolve(dirs.fragments, "packages-desc.md");
md.log(await fs.promises.readFile(headerPath, "utf-8"));
md.log(`<table>`);
for (let [groupID, gr] of Object.entries(pkgShapesData)) {
const prime = gr.subGroups[groupID];
const familyName = buildName("\u00a0", ...prime.family.split(" "));
const sTtcName = buildName("-", "SuperTTC", groupID, argv.version);
const ttcName = buildName("-", "PkgTTC", groupID, argv.version);
const proportionPrefix = gr.quasiProportional ? "Quasi-proportional" : "Monospace";
const desc = `<i>${proportionPrefix}, ${prime.desc}</i>`;
const img = ImgX(`${imagePrefix}/package-sample-${groupID}`);
let ttcCells = [`<td colspan="4">&nbsp;</td>`];
const hasSpacings = Object.entries(gr.subGroups).length > 1;
if (hasSpacings) {
const sTtcLink = `${DownloadLinkPrefix}/${sTtcName}.zip`;
const ttcLink = `${DownloadLinkPrefix}/${ttcName}.zip`;
ttcCells = [
`<td><b><a href="${sTtcLink}">Super\u00A0TTC</b></td>`,
`<td><b><a href="${ttcLink}">TTC</b></td>`,
`<td colspan="2">&nbsp;</td>`
];
}
md.log(
`<tr>`,
`<td colspan="3"><b>&#x1F4E6; ${familyName}</b> — ${desc}</td>`,
...ttcCells,
`</tr>`
);
md.log(
`<tr>`,
`<td><b>&nbsp;&nbsp;└ Sub-packages</b></td>`,
`<td><b>Spacing</b></td>`,
`<td><b>Ligatures</b></td>`,
`<td colspan="4"><b>Downloads</b></td>`,
`</tr>`
);
let lastSubGroupID = null;
for (const [subGroupID, subGr] of Object.entries(gr.subGroups)) {
lastSubGroupID = subGroupID;
}
for (const [subGroupID, subGr] of Object.entries(gr.subGroups)) {
const [spacingDesc, ligation] = Spacings[subGr.spacing];
const createLink = (label, prefix) => {
const fileName = buildName("-", prefix, subGroupID, argv.version);
const downloadLink = `${DownloadLinkPrefix}/${fileName}.zip`;
return `<b><a href="${downloadLink}">${label}</a></b>`;
};
const leader = "&nbsp;&nbsp;&nbsp;&nbsp;" + (subGroupID === lastSubGroupID ? "└" : "├");
const superTtcPrefix = hasSpacings ? "SuperTTC-SGr" : "SuperTTC";
const ttcPrefix = hasSpacings ? "PkgTTC-SGr" : "PkgTTC";
md.log(
`<tr>`,
`<td>${leader}&nbsp;<b>${noBreak(subGr.family)}</b></td>`,
`<td>${spacingDesc}</td>`,
`<td>${flag(ligation)}</td>`,
`<td>${createLink("Super\u00A0TTC", superTtcPrefix)}</td>`,
`<td>${createLink("TTC", ttcPrefix)}</td>`,
`<td>${createLink("TTF", "PkgTTF")}&nbsp;` +
`(${createLink("Unhinted", "PkgTTF-Unhinted")})</td>`,
`<td>${createLink("WebFont", "PkgWebFont")}&nbsp;` +
`(${createLink("Unhinted", "PkgWebFont-Unhinted")})</td>`,
`</tr>`
);
}
md.log(`<tr>`, `<td colspan="8">${img}</td>`, `</tr>`);
}
md.log(`</table>\n`);
return md;
}
function buildName(j, ...parts) {
return parts.filter(x => !!x).join(j);
}
function noBreak(s) {
return s.replace(/ /g, "\u00a0");
}
const Spacings = {
// spacingDesc, ligation
type: ["Default", true],
term: ["Terminal", true],
fixed: ["Fixed", false],
"quasi-proportional": ["Default", false]
};
function flag(f) {
return f ? "<b>Yes</b>" : "No";
}

View file

@ -0,0 +1,12 @@
import fs from "fs";
import path from "path";
import { MdCol } from "../md-format-tools.mjs";
export default async function processPrivateBuildPlans(argv, dirs) {
const md = new MdCol("Section-Private-Build-Plan-Sample");
const tomlPath = path.resolve(argv.projectRoot, "private-build-plans.sample.toml");
const toml = await fs.promises.readFile(tomlPath, "utf-8");
md.log("```toml\n" + toml + "```");
return md;
}

View file

@ -0,0 +1,27 @@
import { parseVariantsData } from "@iosevka/data-export/variants-data";
import { ImgX, MdCol } from "../md-format-tools.mjs";
export default async function processSsOt(argv, dirs) {
const variantsData = await parseVariantsData(argv);
const md = new MdCol("Section-OT-Stylistic-Sets");
md.log(`<table>`);
for (const ss of variantsData.composites) {
if (!ss.rank) continue;
{
md.log(`<tr>`);
md.log(`<td colspan="2"><code>${ss.tag}</code> — ${ss.description}</td>`);
md.log(`</tr>`);
}
{
md.log(
`<tr>`,
`<td>${ImgX(`${dirs.images}/ss-u-${ss.tag}-${ss.rank}`)}</td>`,
`<td>${ImgX(`${dirs.images}/ss-i-${ss.tag}-${ss.rank}`)}</td>`,
`</tr>`
);
}
}
md.log(`</table>`);
return md;
}

View file

@ -0,0 +1,19 @@
import fs from "fs";
import path from "path";
import { parseVariantsData } from "@iosevka/data-export/variants-data";
import { MdCol } from "../md-format-tools.mjs";
export default async function processSsStyles(argv, dirs) {
const variantsData = await parseVariantsData(argv);
const md = new MdCol("Section-Stylistic-Sets");
const headerPath = path.resolve(dirs.fragments, "description-stylistic-sets.md");
md.log(await fs.promises.readFile(headerPath, "utf-8"));
for (const gr of variantsData.composites) {
if (!gr.rank) continue;
md.log(` - \`${gr.tag}\`: Set character variant to “${gr.description}”.`);
}
md.log(` - Other build plans configuration, using \`inherits = "buildPlans.<Plan name>"\`.`);
return md;
}