Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catch Docusaurus build issues #498

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
59 changes: 58 additions & 1 deletion server/config-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,41 @@ export const checkURLsForCorrespondingFiles = (
}, []);
};

// checkForRedirectsFromExistingFiles returns an array of redirects in which the
// source corresponds to a file at a path rooted at dirRoot.
export const checkForRedirectsFromExistingFiles = (
dirRoot: string,
redirects: Redirect[]
): Redirect[] => {
let result: Redirect[] = [];

redirects.forEach((r) => {
if (correspondingFileExistsForURL(dirRoot, r.source)) {
result.push(r);
}
});
return result;
};

// checkDuplicateRedirects checks the provided redirects for duplicates and
// returns an array of Redirect objects. Duplicate checks are based on the
// source of each redirect.
export const checkDuplicateRedirects = (redirects: Redirect[]): Redirect[] => {
const result: Redirect[] = [];
const uniques = new Set();
redirects.forEach((r) => {
if (uniques.has(r.source)) {
result.push(r);
return;
}
uniques.add(r.source);
});
return result;
};

// checkURLForCorrespondingFile determines whether a file exists in the content
// directory rooted at dirRoot for the file corresponding to the provided URL path.// If a file does not exist, it returns false.
// directory rooted at dirRoot for the file corresponding to the provided URL path.
// If a file does not exist, it returns false.
const correspondingFileExistsForURL = (
dirRoot: string,
urlpath: string
Expand Down Expand Up @@ -326,6 +359,30 @@ export const loadConfig = (version: string) => {
);
}

const redirsFrom = checkForRedirectsFromExistingFiles(
join("content", version, "docs", "pages"),
config.redirects
);

if (redirsFrom.length > 0) {
throw new Error(
"Error parsing docs config file " +
join("content", version, "docs", "config.json") +
': Each of the following redirects includes a "source" that corresponds to an existing file: ' +
JSON.stringify(redirsFrom, null, 2)
);
}

const duplicateRedirects = checkDuplicateRedirects(config.redirects);
if (duplicateRedirects.length > 0) {
throw new Error(
"Error parsing docs config file " +
join("content", version, "docs", "config.json") +
": Found redirects with duplicate sources: " +
JSON.stringify(duplicateRedirects, null, 2)
);
}

validateConfig<Config>(validator, config);

config.navigation.forEach((item, i) => {
Expand Down
5 changes: 5 additions & 0 deletions server/fixtures/includes-vars-erroneous-include.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Installation

Here is a test for including variables in an MDX file.

(!install-version.mdx version="10" unsupport="9" !)
15 changes: 15 additions & 0 deletions server/remark-includes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,21 @@ const resolveIncludes = ({
content = content.replace(varRegexp, finalVal);
}

// Catch unresolved parameters, which can break docs builds
const paramRE = new RegExp(`{{ ?\\w+ ?}}`, "g");
const unresolvedParams = Array.from(content.matchAll(paramRE));
if (unresolvedParams.length > 0) {
const errs = unresolvedParams
.map((el) => {
return el[0];
})
.join(",");

error =
`${includePath}: the following partial parameters were not assigned and have no default value: ` +
errs;
}

return content;
} else {
error = `Wrong import path ${includePath} in file ${filePath}.`;
Expand Down
93 changes: 92 additions & 1 deletion uvu-tests/config-docs.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { Redirect } from "next/dist/lib/load-custom-routes";

Check failure on line 1 in uvu-tests/config-docs.test.ts

View workflow job for this annotation

GitHub Actions / Lint code base

Duplicate identifier 'Redirect'.
import { suite } from "uvu";
import * as assert from "uvu/assert";
import { Config, checkURLsForCorrespondingFiles } from "../server/config-docs";
import {
Config,
checkURLsForCorrespondingFiles,
checkForRedirectsFromExistingFiles,
checkDuplicateRedirects,
} from "../server/config-docs";
import { generateNavPaths } from "../server/pages-helpers";
import { randomUUID } from "crypto";
import { join } from "path";
import { Volume, createFsFromVolume } from "memfs";
import type { Redirect } from "next/dist/lib/load-custom-routes";

Check failure on line 14 in uvu-tests/config-docs.test.ts

View workflow job for this annotation

GitHub Actions / Lint code base

Duplicate identifier 'Redirect'.

const Suite = suite("server/config-docs");

Expand Down Expand Up @@ -459,4 +465,89 @@
);
});

Suite("Checks for duplicate redirects", () => {
const redirects: Array<Redirect> = [
{
source: "/getting-started/",
destination: "/get-started/",
permanent: true,
},
{
source: "/getting-started/",
destination: "/get-started/",
permanent: true,
},
{
source: "/application-access/",
destination: "/connecting-apps/",
permanent: true,
},
{
source: "/application-access/",
destination: "/connecting-apps/",
permanent: true,
},
{
source: "/database-access/",
destination: "/connecting-databases/",
permanent: true,
},
];

const expected: Array<Redirect> = [
{
source: "/getting-started/",
destination: "/get-started/",
permanent: true,
},
{
source: "/application-access/",
destination: "/connecting-apps/",
permanent: true,
},
];

const actual = checkDuplicateRedirects(redirects);
assert.equal(actual, expected);
});

Suite("Checks for redirects from existing paths", () => {
const redirects: Array<Redirect> = [
{
source: "/contact/offices/",
destination: "/get-in-touch/offices/",
permanent: true,
},
{
source: "/locations/",
destination: "/contact/offices/",
permanent: true,
},
{
source: "/about/projects/project1/",
destination: "/project1/",
permanent: true,
},
];

const expected: Array<Redirect> = [
{
source: "/contact/offices/",
destination: "/get-in-touch/offices/",
permanent: true,
},
{
source: "/about/projects/project1/",
destination: "/project1/",
permanent: true,
},
];

const actual = checkForRedirectsFromExistingFiles(
join("server", "fixtures", "fake-content"),
redirects
);
assert.equal(actual, expected);
});

Suite.run();
21 changes: 21 additions & 0 deletions uvu-tests/remark-includes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,27 @@ Suite("Resolves template variables in includes", () => {
assert.equal(result, expected);
});

Suite("Throws an error if a variable is unresolved and has no default", () => {
const value = readFileSync(
resolve("server/fixtures/includes-vars-erroneous-include.mdx"),
"utf-8"
);

const out = transformer(
{
value,
path: "/content/4.0/docs/pages/filename.mdx",
},
{ lint: true }
);

assert.equal(out.messages.length, 1);
assert.equal(
out.messages[0].reason,
"The following partial parameters were not assigned and have no default value: {{ unsupported }}"
);
});

Suite(
"Resolves relative links in partials based on the path of the partial",
() => {
Expand Down
Loading