Catalog: an address passes when an allowed one leads it and only punctuation follows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ab42b6f05b
commit
6eef671f14
2 files changed
+8
-9
No files matched your search
+1
-9
@@ -37,14 +37,6 @@ function time(value) {
|
||||
return zone && at.getUTCMonth() === mo - 1 && at.getUTCDate() === d && h < 24 && mi < 60 && sec < 60 && !Number.isNaN(Date.parse(value));
|
||||
}
|
||||
|
||||
/** An address as written in prose, less the punctuation that ends a sentence. */
|
||||
function trim(url) {
|
||||
let out = url.replace(/[.,;:!?*_~]+$/, "");
|
||||
const count = (c) => out.split(c).length - 1;
|
||||
while (out.endsWith(")") && count(")") > count("(")) out = out.slice(0, -1).replace(/[.,;:!?*_~]+$/, "");
|
||||
return out;
|
||||
}
|
||||
|
||||
function fail(where, what) {
|
||||
throw new Error(`${where}: ${what}`);
|
||||
}
|
||||
@@ -156,7 +148,7 @@ function readme(dir, app) {
|
||||
const markdown = bytes.toString("utf8");
|
||||
const links = [app.website, app.source].filter(Boolean);
|
||||
if (ENTITY.test(markdown)) fail(where, `write characters as they are, not as references: ${markdown.match(ENTITY)[0]}`);
|
||||
for (const url of markdown.replaceAll("\\", "").match(URLISH) ?? []) if (!links.includes(trim(url))) fail(where, `addresses go only to the website or source: ${url}`);
|
||||
for (const url of markdown.replaceAll("\\", "").match(URLISH) ?? []) if (!links.some((l) => url.startsWith(l) && /^[.,;:!?*_~)]*$/.test(url.slice(l.length)))) fail(where, `addresses go only to the website or source: ${url}`);
|
||||
const walk = (tokens) => {
|
||||
for (const t of tokens) {
|
||||
if (!TOKENS.has(t.type)) fail(where, `${t.type === "html" ? "raw HTML" : t.type === "code" ? "a code block" : t.type} is not allowed: ${t.raw.trim().slice(0, 60)}`);
|
||||
|
||||
@@ -65,6 +65,12 @@ test("addresses in prose may end a sentence or hold parentheses", () => {
|
||||
assert.equal(read(catalog({ app, files: { "README.md": readme } })).apps.length, 1);
|
||||
});
|
||||
|
||||
test("an address may end in punctuation of its own", () => {
|
||||
const app = { ...good, source: "https://github.com/ada/tally_", website: "https://tally.app/?" };
|
||||
const readme = "[Source](https://github.com/ada/tally_) and [site](https://tally.app/?).\n";
|
||||
assert.equal(read(catalog({ app, files: { "README.md": readme } })).apps.length, 1);
|
||||
});
|
||||
|
||||
test("the empty catalog reads", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "showcase-"));
|
||||
mkdirSync(join(root, "apps"));
|
||||
@@ -115,6 +121,7 @@ const bad = [
|
||||
["a picture outside the folder in a README", { files: { "README.md": "\n" } }, /lowercase .png file name/],
|
||||
["inline code in a README", { files: { "README.md": "Run `cargo install tally`.\n" } }, /codespan is not allowed/],
|
||||
["a character reference in a README", { files: { "README.md": "Go https://evil.io/ now\n" } }, /not as references/],
|
||||
["an address that runs on past the website", { files: { "README.md": "See https://github.com/ada/tally.evil.io now\n" } }, /addresses go only/],
|
||||
["an escaped address in a README", { files: { "README.md": "Go https\://evil.io/ now\n" } }, /addresses go only/],
|
||||
["a large README", { files: { "README.md": "a".repeat(10241) } }, /over 10240/],
|
||||
];
|
||||
|
||||
Reference in new issue
Block a user