Skip to content

Commit

Permalink
Tolerate specref API failures during local dev (#4167)
Browse files Browse the repository at this point in the history
Since #4124 was merged, all builds require an HTTP request to
api.specref.org in order to resolve additional bibliographical
references. This may cause issues in local dev in the case of being
offline due to travel or internet hiccups, behind a proxy, etc.

This commit adds a reusable function for cases where a HTTP failure
during local dev is tolerable, and uses it for the bibrefs request.

Running `npm build` will still result in an immediate failure and stack
trace; this is intentional to ensure that nothing slips by during builds
for PR previews, GitHub Pages, or w3.org.
  • Loading branch information
kfranqueiro authored Dec 6, 2024
1 parent 079df5e commit fd31159
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 5 deletions.
14 changes: 9 additions & 5 deletions 11ty/biblio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { readFile } from "fs/promises";
import { glob } from "glob";
import uniq from "lodash-es/uniq";

import { wrapAxiosRequest } from "./common";

export const biblioPattern = /\[\[\??([\w-]+)\]\]/g;

/** Compiles URLs from local biblio + specref for linking in Understanding documents. */
Expand All @@ -12,24 +14,26 @@ export async function getBiblio() {
.replace(/^respecConfig\.localBiblio\s*=\s*/, "(")
.replace("};", "})")
);

const refs: string[] = [];
for (const path of await glob(["guidelines/**/*.html", "understanding/*/*.html"])) {
const content = await readFile(path, "utf8");
let match;
while ((match = biblioPattern.exec(content))) if (!localBiblio[match[1]]) refs.push(match[1]);
}
const uniqueRefs = uniq(refs);

const response = await axios.get(`https://api.specref.org/bibrefs?refs=${uniqueRefs.join(",")}`);

const response = await wrapAxiosRequest(
axios.get(`https://api.specref.org/bibrefs?refs=${uniqueRefs.join(",")}`)
);
const fullBiblio = {
...response.data,
...localBiblio,
};

const resolvedRefs = Object.keys(fullBiblio);
const unresolvedRefs = uniqueRefs.filter((ref) => !resolvedRefs.includes(ref));
if (unresolvedRefs.length) console.warn(`Unresolved biblio refs: ${unresolvedRefs.join(", ")}`);

return fullBiblio;
}
22 changes: 22 additions & 0 deletions 11ty/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/** @fileoverview Common functions used by multiple parts of the build process */

import { AxiosError, type AxiosResponse } from "axios";

import type { Guideline, Principle, SuccessCriterion } from "./guidelines";

/** Generates an ID for heading permalinks. Equivalent to wcag:generate-id in base.xslt. */
Expand Down Expand Up @@ -28,3 +30,23 @@ export function wcagSort(
}
return 0;
}

/**
* Handles HTTP error responses from Axios requests in local dev;
* re-throws error during builds to fail loudly.
* This should only be used for non-critical requests that can tolerate null data
* without major side effects.
*/
export const wrapAxiosRequest = <T, D>(promise: Promise<AxiosResponse<T, D>>) =>
promise.catch((error) => {
if (!(error instanceof AxiosError) || !error.response || !error.request) throw error;
const { response, request } = error;
console.warn(
`AxiosError: status ${response.status} received from ${
request.protocol + "//" + request.host
}${request.path || ""}`
);

if (process.env.ELEVENTY_RUN_MODE === "build") throw error;
else return { data: null };
});

0 comments on commit fd31159

Please sign in to comment.