Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 42 additions & 19 deletions src/w3c/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,24 @@ export async function run(conf) {
}

if (conf.isEd) conf.thisVersion = conf.edDraftURI;
if (conf.isCGBG) validateCGBG(conf);
if (conf.isCGBG) {
validateCGBG(conf);
}
if (conf.isTagEditorFinding && !conf.latestVersion) {
conf.latestVersion = null;
}
if (conf.latestVersion !== null) {
conf.latestVersion = conf.latestVersion
? w3Url(conf.latestVersion)
: w3Url(`${pubSpace}/${conf.shortName}/`);
if (!conf.isNoTrack) {
const exists = await resourceExists(conf.latestVersion);
if (exists === null && conf.specStatus !== "FPWD") {
const msg = `The "Latest published version:" header link points to a URL that does not exist.`;
const hint = docLink`Check that the ${"[shortname]"} is correct and you are using the right ${"[specStatus]"} for this kind of document.`;
showWarning(msg, name, { hint });
}
}
}

if (conf.latestVersion) validateIfAllowedOnTR(conf);
Expand Down Expand Up @@ -469,7 +482,12 @@ export async function run(conf) {
conf.publishISODate = conf.publishDate.toISOString();
conf.shortISODate = ISODate.format(conf.publishDate);
validatePatentPolicies(conf);
await deriveHistoryURI(conf);

// Only derive historyURI if not explicitly suppressed by the user (null).
if (conf.historyURI !== null) {
conf.historyURI = await deriveHistoryURI(conf);
}

if (conf.isTagEditorFinding) {
delete conf.thisVersion;
delete conf.latestVersion;
Expand Down Expand Up @@ -644,7 +662,6 @@ function validateIfAllowedOnTR(conf) {
const msg = docLink`Documents with a status of \`"${conf.specStatus}"\` can't be published on the W3C's /TR/ (Technical Report) space.`;
const hint = docLink`Ask a W3C Team Member for a W3C URL where the report can be published and change ${"[latestVersion]"} to something else.`;
showError(msg, name, { hint });
return;
}
}

Expand Down Expand Up @@ -677,18 +694,23 @@ function derivePubSpace(conf) {

function validateCGBG(conf) {
const reportType = status2text[conf.specStatus];
const latestVersionURL = conf.latestVersion
? new URL(w3Url(conf.latestVersion))
: null;

if (!conf.wg) {
const msg = docLink`The ${"[group]"} configuration option is required for this kind of document (${reportType}).`;
showError(msg, name);
return;
}

if (conf.specStatus.endsWith("-DRAFT") && !conf.latestVersion) {
conf.latestVersion = null;
return;
}

// Deal with final reports
if (conf.isCGFinal) {
const latestVersionURL = conf.latestVersion
? new URL(w3Url(conf.latestVersion))
: null;
// Final report require a w3.org URL.
const isW3C =
latestVersionURL?.origin === "https://www.w3.org" ||
Expand All @@ -703,18 +725,17 @@ function validateCGBG(conf) {
}

async function deriveHistoryURI(conf) {
if (!conf.shortName || conf.historyURI === null || !conf.latestVersion) {
return; // Nothing to do
if (!conf.shortName || !conf.latestVersion) {
return null;
}

const canShowHistory = conf.isEd || trStatus.includes(conf.specStatus);

if (conf.historyURI && !canShowHistory) {
const msg = docLink`The ${"[historyURI]"} can't be used with non /TR/ documents.`;
if (!canShowHistory && conf.historyURI) {
const msg = docLink`The ${"[historyURI]"} can't be used with non-standards track documents.`;
const hint = docLink`Please remove ${"[historyURI]"}.`;
showError(msg, name, { hint });
conf.historyURI = null;
return;
return conf.historyURI;
}

const historyURL = new URL(
Expand All @@ -728,21 +749,23 @@ async function deriveHistoryURI(conf) {
(conf.historyURI && canShowHistory) ||
["FPWD", "DNOTE", "NOTE", "DRY"].includes(conf.specStatus)
) {
conf.historyURI = historyURL.href;
return;
return historyURL.href;
}

// Let's get the history from the W3C.
// Do a fetch HEAD request to see if the history exists...
// We don't discriminate... if it's on the W3C website with a history,
// we show it.
return await resourceExists(historyURL);
}

/** @returns {Promise<string|null>} Final URL after redirects, or null if unreachable. */
async function resourceExists(url) {
try {
const response = await fetch(historyURL, { method: "HEAD" });
if (response.ok) {
conf.historyURI = response.url;
}
const response = await fetch(url, { method: "HEAD" });
return response.ok ? response.url : null;
} catch {
// Ignore fetch errors
return null;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/w3c/templates/cgbg-headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export default (conf, options) => {
>
</dd>`
: ""}
${"latestVersion" in conf // latestVersion can be falsy
${conf.latestVersion !== null
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for undefined as well?

? html`<dt>${l10n.latest_published_version}</dt>
<dd>
${conf.latestVersion
${conf.latestVersion !== ""
? html`<a href="${conf.latestVersion}"
>${conf.latestVersion}</a
>`
Expand Down
52 changes: 33 additions & 19 deletions tests/spec/w3c/headers-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import {
makeDefaultBody,
makeRSDoc,
makeStandardOps,
warningFilters,
} from "../SpecHelper.js";

const headerErrors = errorFilters.filter("w3c/headers");
const headerWarnings = warningFilters.filter("w3c/headers");
const defaultErrors = errorFilters.filter("w3c/defaults");

const findContent = string => {
Expand Down Expand Up @@ -62,26 +64,27 @@ describe("W3C — Headers", () => {
expect(exportedDoc.querySelector(".head details[open]")).toBeTruthy();
});

it("links to the 'kinds of documents' only for W3C documents", async () => {
const statuses = ["FPWD", "WD", "CR", "CRD", "PR", "REC", "NOTE"];
for (const specStatus of statuses) {
for (const specStatus of recTrackStatus) {
it(`links to the 'kinds of documents' only for W3C documents with status ${specStatus}`, async () => {
const doc = await makeRSDoc(
makeStandardOps({ specStatus, group: "webapps" })
);
const w3cLink = doc.querySelector(
`.head a[href='https://www.w3.org/standards/types#${specStatus}']`
);
expect(w3cLink).withContext(`specStatus: ${specStatus}`).toBeTruthy();
}
expect(w3cLink).toBeTruthy();
});
}

for (const specStatus of ["unofficial", "base"]) {
for (const specStatus of noTrackStatus) {
it(`doesn't link to the 'kinds of documents' for non-rec track ${specStatus}`, async () => {
const doc = await makeRSDoc(makeStandardOps({ specStatus }));
const w3cLink = doc.querySelector(
".head a[href='https://www.w3.org/standards/types#UD']"
);
expect(w3cLink).withContext(`specStatus: ${specStatus}`).toBeNull();
}
});
expect(w3cLink).toBeNull();
});
}

describe("prevRecShortname & prevRecURI", () => {
it("takes prevRecShortname and prevRecURI into account", async () => {
Expand Down Expand Up @@ -1448,6 +1451,21 @@ describe("W3C — Headers", () => {
expect(latestVersionLink.textContent).toBe("https://www.w3.org/TR/foo/");
});

it("warns if latestVersion URL doesn't exist", async () => {
const ops = makeStandardOps({
shortName: "foo",
specStatus: "WD",
group: "webapps",
github: "w3c/respec",
});
const doc = await makeRSDoc(ops);
const warnings = headerWarnings(doc);
expect(warnings).toHaveSize(1);
expect(warnings[0].message).toContain(
`The "Latest published version:" header link points to a URL that does not exist`
);
});

it("allows skipping latest published version link in initial ED", async () => {
const ops = makeStandardOps({
specStatus: "ED",
Expand Down Expand Up @@ -1554,19 +1572,15 @@ describe("W3C — Headers", () => {
);
});

for (const specStatus of cgbgStatus.filter(s => s.endsWith("-DRAFT"))) {
for (const specStatus of cgStatus.filter(s => s.endsWith("-DRAFT"))) {
it(`doesn't set latestVersion URL for ${specStatus} status`, async () => {
const ops = makeStandardOps({
shortName: "some-report",
specStatus,
group: "wicg",
});
const doc = await makeRSDoc(ops);
const terms = [...doc.querySelectorAll(".head dt")];
const latestVersion = terms.find(
el => el.textContent.trim() === "Latest published version:"
);
expect(latestVersion).toHaveSize(0);
expect(contains(doc, "dt", "Latest published version:")).toHaveSize(0);
});
}
for (const specStatus of noTrackStatus) {
Expand Down Expand Up @@ -2000,7 +2014,7 @@ describe("W3C — Headers", () => {
{ specStatus: "BG-FINAL", group: "publishingbg" },
];
for (const { specStatus, group } of finalReportStatus) {
it("requires that the ${specStatus} latestVersion be a w3c URL", async () => {
it(`requires that the ${specStatus} latestVersion be a w3c URL`, async () => {
const ops = makeStandardOps({
specStatus,
group,
Expand Down Expand Up @@ -2577,8 +2591,8 @@ describe("W3C — Headers", () => {
);
});

for (const specStatus of trStatus) {
it(`includes the history for "${specStatus}" rec-track status`, async () => {
for (const specStatus of recTrackStatus) {
it(`includes the history for rec-track "${specStatus}" docs`, async () => {
const shortName = `push-api`;
const ops = makeStandardOps({
shortName,
Expand All @@ -2591,7 +2605,7 @@ describe("W3C — Headers", () => {
expect(history).withContext(specStatus).toBeTruthy();
expect(history.nextElementSibling).withContext(specStatus).toBeTruthy();
const historyLink = history.nextElementSibling.querySelector("a");
expect(historyLink).toBeTruthy();
expect(historyLink).withContext(specStatus).toBeTruthy();
expect(historyLink.href).toBe(
`https://www.w3.org/standards/history/${shortName}/`
);
Expand Down
Loading