Ctrl K
ComunidadGuías…

tests/inkCss.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// The stylesheet half of check-ink (scripts/check-ink.mjs), with no browser:
// the two patterns that cut Arabic marks, held out of every stylesheet the
// client ships. The tokens they read are in client/styles/tokens.css, under
// "Leading for a script with marks above and below".
import assert from "node:assert/strict";
import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, it } from "node:test";
import { fileURLToPath } from "node:url";

const client = fileURLToPath(new URL("../client", import.meta.url));

function sheets(dir: string): string[] {
  const found: string[] = [];
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
    const p = join(dir, entry.name);
    if (entry.isDirectory()) found.push(...sheets(p));
    else if (entry.name.endsWith(".css")) found.push(p);
  }
  return found;
}

/** Every declaration block, with its selector and the line it starts on.
 *  Innermost blocks only — an @media wrapper is not a rule. */
function rules(file: string): { where: string; selector: string; body: string }[] {
  const src = readFileSync(file, "utf8").replace(/\/\*[\s\S]*?\*\//g, (c) => c.replace(/[^\n]/g, " "));
  const out = [];
  for (const m of src.matchAll(/([^{};]*)\{([^{}]*)\}/g)) {
    const line = src.slice(0, m.index).split("\n").length;
    out.push({ where: `${file.slice(client.length + 1)}:${line}`, selector: m[1].trim(), body: m[2] });
  }
  return out;
}

const all = sheets(client).flatMap(rules);

describe("ink: the stylesheets", () => {
  it("found the stylesheets", () => {
    assert.ok(all.length > 2000, `only ${all.length} rules read`);
  });

  it("a truncating label clips sideways only", () => {
    // `overflow: hidden` clips both axes, so the marks over and under a
    // one-line label were cut; it also drops a flex item's automatic minimum,
    // which squeezed a long note's outline rows to half a line.
    // `overflow: clip visible` truncates with the same ellipsis and paints
    // the marks. A clamp is the exception, and has its own rule below.
    const bad = all.filter(
      (r) =>
        /text-overflow:\s*ellipsis/.test(r.body) &&
        !/line-clamp/.test(r.body) &&
        /(^|[;\s])overflow:\s*hidden\s*;/.test(r.body),
    );
    assert.deepEqual(
      bad.map((r) => `${r.where} ${r.selector}`),
      [],
      "use `overflow: clip visible; min-width: 0` for a one-line ellipsis",
    );
  });

  it("a clamped snippet sets its leading through --snippet-leading", () => {
    const bad = all.filter(
      (r) => /line-clamp/.test(r.body) && /line-height:\s*[0-9.]+\s*;/.test(r.body),
    );
    assert.deepEqual(
      bad.map((r) => `${r.where} ${r.selector}`),
      [],
      "write `line-height: var(--snippet-leading, <latin value>)`",
    );
  });

  it("the tokens are set for right-to-left blocks and dropped again for left-to-right ones", () => {
    const tokens = readFileSync(join(client, "styles/tokens.css"), "utf8");
    const rtl = /:dir\(rtl\)\s*\{([^}]*)\}/.exec(tokens)?.[1] ?? "";
    const ltr = /:dir\(ltr\)\s*\{([^}]*)\}/.exec(tokens)?.[1] ?? "";
    for (const name of ["--display-leading", "--snippet-leading", "--rule-clearance"]) {
      assert.match(rtl, new RegExp(`${name}:\\s*[0-9.]+(em)?;`), `${name} under :dir(rtl)`);
      assert.match(ltr, new RegExp(`${name}:\\s*initial;`), `${name} reset under :dir(ltr)`);
    }
  });

  it("the editor's headings and the reading view's read the same token", () => {
    const theme = readFileSync(join(client, "editor/theme.ts"), "utf8");
    const reading = readFileSync(join(client, "reading/reading.css"), "utf8");
    assert.match(theme, /lineHeight: "var\(--display-leading, 1\.3\)"/);
    assert.match(theme, /paddingBottom: "var\(--rule-clearance, 0\.2em\)"/);
    assert.match(reading, /\.s-rv \.s-rv-h \{[^}]*line-height: var\(--display-leading, 1\.3\);/);
    assert.match(reading, /\.s-rv \.s-rv-h1 \{[^}]*padding-bottom: var\(--rule-clearance, 0\.2em\);/);
  });
});