Skip to content

Commit

Permalink
make more modular
Browse files Browse the repository at this point in the history
  • Loading branch information
vincerubinetti committed Mar 13, 2024
1 parent 1a17772 commit 379a3fa
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 121 deletions.
45 changes: 26 additions & 19 deletions check.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import { addError, list } from "./core";
import { addError, getList, onExit } from "./core";

// for each redirect
await Promise.all(
list.map(async ({ to }) => {
try {
// do simple request to target url
const response = await fetch(to);
if (
// only fail on certain status codes that might indicate link is "broken"
[
400, 404, 405, 406, 408, 409, 410, 421, 500, 501, 502, 503, 504,
].includes(response.status)
)
throw Error(response.status);
} catch (error) {
addError(`"to: ${to}" may be a broken link\n(${error})`);
}
})
);
onExit();

// check list of redirects for broken links
async function checkList(list) {
return await Promise.all(
// for each redirect
list.map(async ({ to }) => {
try {
// do simple request to target url
const response = await fetch(to);
if (
// only fail on certain status codes that might indicate link is "broken"
[
400, 404, 405, 406, 408, 409, 410, 421, 500, 501, 502, 503, 504,
].includes(response.status)
)
throw Error(response.status);
} catch (error) {
addError(`"to: ${to}" may be a broken link\n(${error})`);
}
})
);
}

await checkList(getList());
154 changes: 80 additions & 74 deletions core.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,108 +3,114 @@ import { resolve } from "path";
import { globSync } from "glob";
import { parse } from "yaml";

// collect (caught) errors to report at end
const errors = [];

// if running in github actions debug mode, do extra logging
export const verbose = !!process.env.RUNNER_DEBUG;

// get yaml files that match glob pattern
const files = globSync("*.y?(a)ml", { cwd: __dirname });
// get full list of redirects
export function getList() {
// get yaml files that match glob pattern
const files = globSync("*.y?(a)ml", { cwd: __dirname });

log("Files", files.join(" "));
log("Files", files.join(" "));

// start combined list of redirects
export const list = [];
// start combined list of redirects
const list = [];

// keep track of duplicate entries
const duplicates = {};
// keep track of duplicate entries
const duplicates = {};

// go through each yaml file
for (const file of files) {
// load file contents
const contents = readFileSync(resolve(__dirname, file), "utf8");
// go through each yaml file
for (const file of files) {
// load file contents
const contents = readFileSync(resolve(__dirname, file), "utf8");

// try to parse as yaml
let data;
try {
data = parse(contents);
} catch (error) {
addError(`Couldn't parse ${file}. Make sure it is valid YAML.`);
continue;
}

// check if top level is list
if (!Array.isArray(data)) {
addError(`${file} is not a list`);
continue;
}

// go through each entry
for (let [index, entry] of Object.entries(data)) {
index = Number(index) + 1;
const trace = `${file} entry ${index}`;

// check if dict
if (typeof entry !== "object") {
addError(`${trace} is not a dict`);
// try to parse as yaml
let data;
try {
data = parse(contents);
} catch (error) {
addError(`Couldn't parse ${file}. Make sure it is valid YAML.`);
continue;
}

// check "from" field
if (!(typeof entry.from === "string" && entry.from.trim())) {
addError(`${trace} "from" field invalid`);
// check if top level is list
if (!Array.isArray(data)) {
addError(`${file} is not a list`);
continue;
}

// check "to" field
if (!(typeof entry.to === "string" && entry.to.trim()))
addError(`${trace} "to" field invalid`);
// go through each entry
for (let [index, entry] of Object.entries(data)) {
index = Number(index) + 1;
const trace = `${file} entry ${index}`;

// check if dict
if (typeof entry !== "object") {
addError(`${trace} is not a dict`);
continue;
}

// check "from" field
if (!(typeof entry.from === "string" && entry.from.trim())) {
addError(`${trace} "from" field invalid`);
continue;
}

// check "to" field
if (!(typeof entry.to === "string" && entry.to.trim()))
addError(`${trace} "to" field invalid`);

// normalize "from" field. lower case, remove leading slashes.
entry.from = entry.from.toLowerCase().replace(/^(\/+)/, "");
// normalize "from" field. lower case, remove leading slashes.
entry.from = entry.from.toLowerCase().replace(/^(\/+)/, "");

// add to combined list
list.push(entry);
// add to combined list
list.push(entry);

// add to duplicate list. record source file and entry number for logging.
duplicates[entry.from] ??= [];
duplicates[entry.from].push({ ...entry, file, index });
// add to duplicate list. record source file and entry number for logging.
duplicates[entry.from] ??= [];
duplicates[entry.from].push({ ...entry, file, index });
}
}
}

// check that any redirects exist
if (!list.length) addError("No redirects");
// check that any redirects exist
if (!list.length) addError("No redirects");

if (verbose) log("Combined redirects list", list);
if (verbose) log("Combined redirects list", list);

// trigger errors for duplicates
for (const [from, entries] of Object.entries(duplicates)) {
const count = entries.length;
if (count <= 1) continue;
const duplicates = entries
.map(({ file, index }) => `\n ${file} entry ${index}`)
.join("");
addError(`"from: ${from}" appears ${count} time(s): ${duplicates}`);
// trigger errors for duplicates
for (const [from, entries] of Object.entries(duplicates)) {
const count = entries.length;
if (count <= 1) continue;
const duplicates = entries
.map(({ file, index }) => `\n ${file} entry ${index}`)
.join("");
addError(`"from: ${from}" appears ${count} time(s): ${duplicates}`);
}

return list;
}

// collect (caught) errors to report at end
const errors = [];

// add error
export function addError(error) {
errors.push(error);
}

// when script finished
process.on("exit", () => {
// report all errors together
if (errors.length) {
process.exitCode = 1;
errors.forEach(logError);
logError(`${errors.length} error(s)`);
} else {
process.exitCode = 0;
log("No errors!");
}
});
// when script finished, report all errors together
export function onExit() {
process.on("exit", () => {
if (errors.length) {
process.exitCode = 1;
errors.forEach(logError);
logError(`${errors.length} error(s)`);
} else {
process.exitCode = 0;
log("No errors!");
}
});
}

// formatted normal log
export function log(message, data) {
Expand Down
63 changes: 35 additions & 28 deletions encode.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,47 @@
import { readFileSync, writeFileSync } from "fs";
import { addError, list, verbose } from "./core";
import { addError, getList, onExit, verbose } from "./core";

// encode redirect list to base64 to obfuscate
const encoded = Buffer.from(JSON.stringify(list)).toString("base64");
onExit();

if (verbose) log("Encoded redirects list", encoded);
// encode list of redirects into redirect script
function encodeList(list) {
// encode redirect list to base64 to obfuscate
const encoded = Buffer.from(JSON.stringify(list)).toString("base64");

// redirect script from website repo
const script = "./website-repo/redirect.js";
if (verbose) log("Encoded redirects list", encoded);

// load contents of script
let contents = "";
try {
contents = readFileSync(script, "utf8").toString();
} catch (error) {
addError(`Couldn't find script file at ${script}`);
}
// redirect script from website repo
const script = "./website-repo/redirect.js";

// load contents of script
let contents = "";
try {
contents = readFileSync(script, "utf8").toString();
} catch (error) {
addError(`Couldn't find script file at ${script}`);
}

// pattern to extract encoded redirect list from script string
const regex = /(list\s*=\s*")([A-Za-z0-9+\/=]*)(")/;
// pattern to extract encoded redirect list from script string
const regex = /(list\s*=\s*")([A-Za-z0-9+\/=]*)(")/;

// get encoded redirect list currently in script
const oldEncoded = contents.match(regex)?.[2];
// get encoded redirect list currently in script
const oldEncoded = contents.match(regex)?.[2];

if (verbose) log("Old encoded redirects list", oldEncoded);
if (verbose) log("Old encoded redirects list", oldEncoded);

// check that we could find it (and thus can replace it)
if (typeof oldEncoded !== "string")
addError("Couldn't find encoded redirects list in redirect script");
// check that we could find it (and thus can replace it)
if (typeof oldEncoded !== "string")
addError("Couldn't find encoded redirects list in redirect script");

// update encoded string in script
const newContents = contents.replace(regex, "$1" + encoded + "$3");
// update encoded string in script
const newContents = contents.replace(regex, "$1" + encoded + "$3");

// write updated redirect script to website repo
try {
writeFileSync(script, newContents, "utf-8");
} catch (error) {
addError(`Couldn't write script file to ${script}`);
// write updated redirect script to website repo
try {
writeFileSync(script, newContents, "utf-8");
} catch (error) {
addError(`Couldn't write script file to ${script}`);
}
}

encodeList(getList());

0 comments on commit 379a3fa

Please sign in to comment.