Run prettier

This commit is contained in:
Ben Edgington
2025-05-24 17:40:38 +01:00
parent 745d9f1f28
commit 422c2b9387
9 changed files with 120 additions and 133 deletions

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

View File

@@ -6,8 +6,7 @@ import { visit } from 'unist-util-visit';
let constantsMap = {};
function addTooltips() {
return function(tree) {
return function (tree) {
try {
visit(tree, 'inlineCode', (node, index, parent) => {
// HTML in headings causes problems for the page index, so skip these
@@ -20,15 +19,14 @@ function addTooltips() {
node.children = undefined;
}
}
})
});
} catch (err) {
console.error(err);
}
}
};
}
export default function(options) {
export default function (options) {
// Read the constants file and store it for later
const constantsFile = options?.constantsFile || '';
try {
@@ -43,9 +41,7 @@ export default function(options) {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
markdown: {
remarkPlugins: [
addTooltips,
],
remarkPlugins: [addTooltips],
},
});
},

View File

@@ -1,60 +1,62 @@
import { CONTINUE, SKIP, visit } from 'unist-util-visit';
import { fromHtmlIsomorphic } from 'hast-util-from-html-isomorphic'
import { fromHtmlIsomorphic } from 'hast-util-from-html-isomorphic';
import { toString } from 'hast-util-to-string';
// Add IDs and SVG permalinks to headings h3 to h6
// (rehype-autolink-headings is good, but can't be configured to ignore h1 and h2)
const anchor = fromHtmlIsomorphic('<a class="anchor" ariaHidden="true"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>', {fragment: true}).children[0];
const anchor = fromHtmlIsomorphic(
'<a class="anchor" ariaHidden="true"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>',
{ fragment: true },
).children[0];
// The headings to process
const headings = ['h3', 'h4', 'h5', 'h6'];
// Should match the method in bin/build/checks/links.pl
function slugIt(heading) {
return (
toString(heading)
.trim()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^a-z0-9_-]/g, '')
);
return toString(heading)
.trim()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^a-z0-9_-]/g, '');
}
function autolinkHeadings() {
return function(tree) {
return function (tree) {
try {
visit(tree, 'element', node => {
visit(tree, 'element', (node) => {
if (headings.indexOf(node.tagName) === -1) {
return CONTINUE;
}
const newAnchor = structuredClone(anchor);
const newAnchor = structuredClone(anchor);
if (node.properties.id) {
newAnchor.properties = { ...newAnchor.properties, href: '#' + node.properties.id };
newAnchor.properties = {
...newAnchor.properties,
href: '#' + node.properties.id,
};
} else {
const id = slugIt(node);
newAnchor.properties = { ...newAnchor.properties, href: '#' + id };
node.properties.id = id;
}
node.children = [ newAnchor ].concat(node.children);
node.children = [newAnchor].concat(node.children);
return SKIP;
})
});
} catch (err) {
console.error(err);
}
}
};
}
export default function() {
export default function () {
return {
name: 'myAutolinkHeadings',
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
markdown: {
rehypePlugins: [
autolinkHeadings,
],
rehypePlugins: [autolinkHeadings],
},
});
},

View File

@@ -5,13 +5,13 @@ function buildChecks(logger) {
runChecks(logger, false);
}
export default function() {
export default function () {
let doChecks;
return {
name: 'myBuildChecks',
hooks: {
'astro:config:setup': ({ command }) => {
doChecks = (command === 'build' && process.env.UE_NOCHECK === undefined);
doChecks = command === 'build' && process.env.UE_NOCHECK === undefined;
},
'astro:config:done': ({ logger }) => {
if (doChecks) {

View File

@@ -3,14 +3,12 @@ import { visit, SKIP } from 'unist-util-visit';
// Clean up any weird HTML artefacts, especially those that fail validation
function cleanupHtml() {
return function(tree) {
return function (tree) {
try {
// Remove `is:raw=""` that's on `code` elements, probably from Prism.
visit(tree, 'element', node => {
if (node.tagName == 'code'
&& node.properties['is:raw'] !== undefined) {
delete(node.properties['is:raw']);
visit(tree, 'element', (node) => {
if (node.tagName == 'code' && node.properties['is:raw'] !== undefined) {
delete node.properties['is:raw'];
}
});
@@ -19,23 +17,20 @@ function cleanupHtml() {
parent.children.splice(index, 1);
return SKIP;
});
} catch (err) {
console.error(err);
}
}
};
}
export default function() {
export default function () {
return {
name: 'myCleanupHtml',
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
markdown: {
rehypePlugins: [
cleanupHtml,
],
rehypePlugins: [cleanupHtml],
},
});
},

View File

@@ -4,44 +4,43 @@ import { visit } from 'unist-util-visit';
// It seems that [Astro does not do this](https://github.com/withastro/astro/issues/3626)
function fixupLinks(basePath) {
return function(tree) {
return function (tree) {
try {
visit(tree, 'element', node => {
if (node.tagName == 'a'
&& node.properties.href) {
visit(tree, 'element', (node) => {
if (node.tagName == 'a' && node.properties.href) {
// Add basePath prefix to local URLs that lack it
// [Astro does not do this](https://github.com/withastro/astro/issues/3626)
if(node.properties.href.startsWith('/')
&& !node.properties.href.startsWith(basePath + '/')) {
if (
node.properties.href.startsWith('/') &&
!node.properties.href.startsWith(basePath + '/')
) {
node.properties.href = basePath + node.properties.href;
}
// Add rel="external noopener" and target="_blank" attributes to off-site links
if(!node.properties.href.startsWith('/')
&& !node.properties.href.startsWith('#')) {
if (
!node.properties.href.startsWith('/') &&
!node.properties.href.startsWith('#')
) {
node.properties.rel = ['external', 'noopener'];
node.properties.target = '_blank';
}
}
})
});
} catch (err) {
console.error(err);
}
}
};
}
export default function() {
export default function () {
return {
name: 'myFixupLinks',
hooks: {
'astro:config:setup': ({ config, updateConfig }) => {
updateConfig({
markdown: {
rehypePlugins: [
[fixupLinks, config.base],
],
rehypePlugins: [[fixupLinks, config.base]],
},
});
},

View File

@@ -7,7 +7,7 @@ function writeHtaccess(base, dir, logger) {
logger.info(`Wrote .htaccess file to ${file}`);
}
export default function(base) {
export default function (base) {
return {
name: 'myHtaccess',
hooks: {

View File

@@ -5,12 +5,14 @@ import fs from 'fs';
// File scoped to accumulate the index across calls to mySearchIndex
const searchIndex = [];
function isExcludedFrontmatter (frontmatter, exclude) {
function isExcludedFrontmatter(frontmatter, exclude) {
for (let i = 0; i < exclude.frontmatter.length; i++) {
const test = exclude.frontmatter[i];
const [key, ...rest] = Object.keys(test);
if (Object.prototype.hasOwnProperty.call(frontmatter, key)
&& frontmatter[key] == test[key]) {
if (
Object.prototype.hasOwnProperty.call(frontmatter, key) &&
frontmatter[key] == test[key]
) {
return true;
}
}
@@ -18,45 +20,42 @@ function isExcludedFrontmatter (frontmatter, exclude) {
}
// Recursively concatenate all text in child nodes while respecting exclusions
function getText (node, exclude) {
function getText(node, exclude) {
if (node.type === 'text') {
// [\u202F\u00A0] is a non-breaking space
return node.value.replace(/[\u202F\u00A0]/, ' ');
}
if (node.type !== 'element'
|| matches(exclude.ignore, node)) {
if (node.type !== 'element' || matches(exclude.ignore, node)) {
return '';
}
return node.children.map( node => {return getText(node, exclude)}).join('');
return node.children
.map((node) => {
return getText(node, exclude);
})
.join('');
}
function getChunks (tree, chunkTypes, exclude) {
function getChunks(tree, chunkTypes, exclude) {
const counts = Array(chunkTypes.length).fill(0);
let chunks = [];
// Walk the tree until we find an element we want to treat as a chunk, then get
// all its text content.
visit(tree, 'element', node => {
visit(tree, 'element', (node) => {
if (matches(exclude.ignore, node)) {
return SKIP;
}
for (let idx = 0; idx < chunkTypes.length; idx++) {
const type = chunkTypes[idx];
if (matches(type.query, node)) {
const text = getText(node, exclude);
if (text !== '') {
const tagName = node.tagName.toLowerCase();
let id = node.properties?.id;
if ( id === undefined) {
if (id === undefined) {
// Edit the element's ID so we can find it from the search page later
id = tagName + '_' + counts[idx];
node.properties.id = id;
@@ -72,7 +71,7 @@ function getChunks (tree, chunkTypes, exclude) {
});
}
return SKIP;
};
}
}
return CONTINUE;
@@ -82,21 +81,20 @@ function getChunks (tree, chunkTypes, exclude) {
}
function includePage(frontmatter, exclude) {
return (frontmatter !== undefined
&& isExcludedFrontmatter(frontmatter, exclude) === false
&& exclude.pages?.indexOf(frontmatter.path) === -1);
return (
frontmatter !== undefined &&
isExcludedFrontmatter(frontmatter, exclude) === false &&
exclude.pages?.indexOf(frontmatter.path) === -1
);
}
function buildSearchIndex(options) {
const { chunkTypes, exclude, logger } = { ...options };
return function (tree, file) {
const frontmatter = file.data.astro.frontmatter;
if (includePage(frontmatter, exclude)) {
logger.debug('Processing ' + frontmatter.path);
const chunks = getChunks(tree, chunkTypes, exclude);
@@ -106,19 +104,15 @@ function buildSearchIndex(options) {
titles: frontmatter.titles,
},
chunks: chunks,
}
};
searchIndex.push(pageIndexData);
} else {
logger.debug('Ignoring ' + frontmatter.path);
}
}
};
}
function writeSearchIndex(dir, file, logger) {
const fileName = dir.pathname + file;
if (searchIndex.length) {
@@ -131,10 +125,9 @@ function writeSearchIndex(dir, file, logger) {
logger.info('Wrote search index to ' + fileName);
}
export default function(options) {
export default function (options) {
if (options.enabled === false) {
return {name: 'my-search-index'};
return { name: 'my-search-index' };
}
return {
@@ -144,9 +137,7 @@ export default function(options) {
'astro:config:setup': ({ updateConfig, logger }) => {
updateConfig({
markdown: {
rehypePlugins: [
[buildSearchIndex, { ...options, logger: logger }],
],
rehypePlugins: [[buildSearchIndex, { ...options, logger: logger }]],
},
});
},

View File

@@ -17,15 +17,15 @@ const addTitle = {
exit: (node, parentNode) => {
if (node.name === 'svg' && parentNode.type === 'root') {
const hasTitle = node.children.some(
(child) => child.type === 'element' && child.name === 'title'
)
(child) => child.type === 'element' && child.name === 'title',
);
if (!hasTitle) {
const titleElement = {
type: 'element',
name: 'title',
attributes: {},
children: [],
}
};
Object.defineProperty(titleElement, 'parentNode', {
writable: true,
value: node,
@@ -33,20 +33,20 @@ const addTitle = {
const titleContents = {
type: 'text',
value: params.titleText,
}
};
Object.defineProperty(titleContents, 'parentNode', {
writable: true,
value: titleElement,
});
titleElement.children.push(titleContents)
titleElement.children.push(titleContents);
node.children.unshift(titleElement);
}
}
},
},
}
};
},
}
};
// See https://www.npmjs.com/package/svgo
const plugins = [
@@ -56,39 +56,38 @@ const plugins = [
'removeXMLNS',
{
name: 'addAttributesToSVGElement',
params: {attribute: {'role': 'img'}},
params: { attribute: { role: 'img' } },
},
]
];
const addTitleSettings = {
const addTitleSettings = {
name: addTitle.name,
type: addTitle.type,
active: addTitle.active,
fn: addTitle.fn,
params: undefined,
}
};
const addAttributes = {
name: 'addAttributesToSVGElement',
params: undefined,
}
name: 'addAttributesToSVGElement',
params: undefined,
};
function inlineSvg(options) {
const filePath = options.filePath || '';
const cachePathTmp = options.cachePath;
const cachePath = cachePathTmp.endsWith('/') ? cachePathTmp : cachePathTmp + '/';
const { logger, doCache} = options;
const cachePath = cachePathTmp.endsWith('/')
? cachePathTmp
: cachePathTmp + '/';
const { logger, doCache } = options;
return function (tree) {
try {
visit(tree, 'paragraph', async node => {
visit(tree, 'paragraph', async (node) => {
if (node.children[0].type == 'image') {
const image = node.children[0];
if (image.url.endsWith('.svg')) {
const originalSvg = fs.readFileSync(filePath + image.url, 'utf8');
const basename = path.basename(image.url, '.svg');
@@ -96,10 +95,10 @@ function inlineSvg(options) {
const digest = getHashDigest(basename, 'md5', 'base52', 4);
// Configure the SVGO addAttributes plugin to add an ID to SVG element
addAttributes['params'] = {attribute: {id: basename + "-svg"}};
addAttributes['params'] = { attribute: { id: basename + '-svg' } };
// Configure our custom plugin that adds a title element
addTitleSettings['params'] = {titleText: image.alt};
addTitleSettings['params'] = { titleText: image.alt };
// If the cachePath option is provided, we load the optimised SVG from there
// when it exists and is newer than the original SVG. If a cached version is
@@ -107,22 +106,20 @@ function inlineSvg(options) {
const origMtime = fs.statSync(filePath + image.url).mtime;
const cacheFile = doCache ? cachePath + basename + '.svg' : null;
const goodCache = doCache
&& fs.existsSync(cacheFile)
&& (fs.statSync(cacheFile).mtime > origMtime);
const goodCache =
doCache &&
fs.existsSync(cacheFile) &&
fs.statSync(cacheFile).mtime > origMtime;
let svg;
if (goodCache) {
svg = fs.readFileSync(cacheFile, 'utf8');
logger.debug(`Using cached ${basename}.svg`);
} else {
svg = optimize(
originalSvg,
{
path: digest,
plugins: plugins.concat([addTitleSettings, addAttributes])
}
).data;
svg = optimize(originalSvg, {
path: digest,
plugins: plugins.concat([addTitleSettings, addAttributes]),
}).data;
logger.debug(`Optimising ${basename}.svg`);
if (doCache) {
fs.writeFileSync(cacheFile, svg);
@@ -138,14 +135,14 @@ function inlineSvg(options) {
node.children = [];
}
}
})
});
} catch (err) {
console.error(err);
}
}
};
}
export default function(options) {
export default function (options) {
return {
name: 'mySvgInline',
hooks: {
@@ -156,10 +153,14 @@ export default function(options) {
if (fs.statSync(options.cachePath).isDirectory()) {
doCache = true;
} else {
logger.warn(`Not caching SVGs: ${options.cachePath} is not a directory`);
logger.warn(
`Not caching SVGs: ${options.cachePath} is not a directory`,
);
}
} catch(e) {
logger.warn(`Not caching SVGs: ${options.cachePath} does not exist`);
} catch (e) {
logger.warn(
`Not caching SVGs: ${options.cachePath} does not exist`,
);
}
} else {
logger.info('Not caching SVGs: no cachePath provided');