2023-05-27 01:11:28 +02:00
|
|
|
import * as cheerio from 'cheerio';
|
2023-06-07 21:44:07 +02:00
|
|
|
import stripIndent from 'strip-indent';
|
2023-05-27 01:11:28 +02:00
|
|
|
|
|
|
|
import { codeBlock } from './components';
|
2023-06-07 22:36:06 +02:00
|
|
|
import { liquidEngine } from './engines';
|
2023-05-27 01:11:28 +02:00
|
|
|
|
|
|
|
const links: Record<string, string> = {
|
|
|
|
number: '/documentation/values/numbers',
|
|
|
|
string: '/documentation/values/strings',
|
|
|
|
'quoted string': '/documentation/values/strings#quoted',
|
|
|
|
'unquoted string': '/documentation/values/strings#unquoted',
|
|
|
|
color: '/documentation/values/colors',
|
|
|
|
list: '/documentation/values/lists',
|
|
|
|
map: '/documentation/values/maps',
|
|
|
|
boolean: '/documentation/values/booleans',
|
|
|
|
null: '/documentation/values/null',
|
|
|
|
function: '/documentation/values/functions',
|
|
|
|
selector: '/documentation/modules/selector#selector-values',
|
|
|
|
};
|
|
|
|
|
|
|
|
const returnTypeLink = (returnType: string) =>
|
|
|
|
returnType
|
|
|
|
.split('|')
|
|
|
|
.map((type) => {
|
|
|
|
type = type.trim();
|
|
|
|
const link = links[type];
|
|
|
|
if (!link) {
|
|
|
|
throw new Error(`Unknown type ${type}`);
|
|
|
|
}
|
|
|
|
return `<a href="${link}">${type}</a>`;
|
|
|
|
})
|
|
|
|
.join(' | ');
|
|
|
|
|
|
|
|
/** Renders API docs for a Sass function (or mixin).
|
|
|
|
*
|
|
|
|
* The function's name is parsed from the signature. The API description is
|
2023-06-07 22:36:06 +02:00
|
|
|
* passed as an HTML block. If `returns:type` is passed as the last argument,
|
2023-05-27 01:11:28 +02:00
|
|
|
* it's included as the function's return type.
|
|
|
|
*
|
|
|
|
* Multiple signatures may be passed, in which case they're all included in
|
|
|
|
* sequence.
|
|
|
|
*/
|
|
|
|
export function _function(content: string, ...signatures: string[]) {
|
|
|
|
// Parse the last argument as the return type, if it's present
|
|
|
|
const returns = signatures.at(-1)?.match(/returns?:\s*(.*)/)?.[1];
|
2023-06-07 21:44:07 +02:00
|
|
|
if (returns) {
|
|
|
|
signatures.pop();
|
|
|
|
}
|
2023-05-27 01:11:28 +02:00
|
|
|
|
|
|
|
// Highlight each signature
|
|
|
|
const names: string[] = [];
|
|
|
|
const highlightedSignatures = signatures.map((signature) => {
|
2023-06-07 21:44:07 +02:00
|
|
|
signature = stripIndent(signature).trim();
|
2023-05-27 01:11:28 +02:00
|
|
|
const [name] = signature.split('(', 2);
|
|
|
|
const nameWithoutNamespace = name.split('.').at(-1) || name;
|
|
|
|
const html = codeBlock(`@function ${signature}`, 'scss');
|
|
|
|
const $ = cheerio.load(html);
|
|
|
|
const signatureElements = $('pre code')
|
|
|
|
.contents()
|
|
|
|
.filter((index, element) => $(element).text() !== '@function');
|
2023-06-07 21:44:07 +02:00
|
|
|
// Add a class to make it easier to index function documentation.
|
2023-05-27 01:11:28 +02:00
|
|
|
if (!names.includes(nameWithoutNamespace)) {
|
|
|
|
names.push(nameWithoutNamespace);
|
|
|
|
const nameEl = signatureElements
|
|
|
|
.filter((index, element) => {
|
|
|
|
return $(element).text() == nameWithoutNamespace;
|
|
|
|
})
|
|
|
|
.eq(0);
|
|
|
|
nameEl.addClass('docSearch-function');
|
|
|
|
nameEl.attr('name', name);
|
|
|
|
}
|
|
|
|
return signatureElements
|
|
|
|
.toArray()
|
|
|
|
.map((el) => $.html(el))
|
|
|
|
.join('')
|
2023-05-27 02:23:55 +02:00
|
|
|
.trim();
|
2023-05-27 01:11:28 +02:00
|
|
|
});
|
|
|
|
|
2023-06-07 22:36:06 +02:00
|
|
|
// Render the final HTML
|
|
|
|
return liquidEngine.renderFile('function', {
|
|
|
|
names,
|
|
|
|
signatures: highlightedSignatures.join('\n'),
|
|
|
|
content,
|
|
|
|
returns: returns ? returnTypeLink(returns) : null,
|
2023-05-27 01:11:28 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access,
|
|
|
|
@typescript-eslint/no-unsafe-call,
|
|
|
|
@typescript-eslint/no-explicit-any */
|
|
|
|
export default function typePlugin(eleventyConfig: any) {
|
|
|
|
eleventyConfig.addPairedLiquidShortcode('function', _function);
|
|
|
|
}
|