Skip to content
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
5,206 changes: 3,679 additions & 1,527 deletions package-lock.json

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"@limetech/stencil-router": "^1.0.1",
"@stencil/core": "4.38.0",
"@stencil/sass": "3.2.2",
"@types/jest": "25.2.3",
"@types/jest": "^25.2.3",
"@types/prismjs": "^1.16.5",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
Expand Down Expand Up @@ -92,19 +92,19 @@
"lnk": "^1.1.0",
"lodash": "^4.17.23",
"node-cleanup": "^2.1.2",
"rehype-raw": "^4.0.2",
"rehype-slug": "^4.0.1",
"rehype-stringify": "^8.0.0",
"remark-admonitions": "^1.2.1",
"remark-frontmatter": "^2.0.0",
"remark-parse": "^8.0.2",
"remark-parse-yaml": "0.0.3",
"remark-rehype": "^7.0.0",
"rehype-raw": "^7.0.0",
"rehype-slug": "^6.0.0",
"rehype-stringify": "^10.0.1",
"remark-directive": "^3.0.1",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
"typedoc": "^0.23.28",
"unified": "^9.0.0",
"unist-util-flatmap": "^1.0.0",
"unist-util-map": "^2.0.1",
"unist-util-visit": "^2.0.2"
"unified": "^11.0.5",
"unist-util-map": "^4.0.0",
"unist-util-visit": "^5.1.0",
"yaml": "^2.8.3"
},
"repository": {
"type": "git",
Expand Down
112 changes: 112 additions & 0 deletions src/kompendium/markdown-admonitions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import type { Node, Parent } from 'unist';
import { visit } from 'unist-util-visit';
import { isParent } from './markdown-nodes';

interface DirectiveNode extends Parent {
name: string;
data?: Record<string, unknown>;
}

const ADMONITION_TYPES = new Map([
['note', 'secondary'],
['important', 'info'],
['tip', 'success'],
['warning', 'danger'],
['caution', 'warning'],
]);

const TYPES_PATTERN = [...ADMONITION_TYPES.keys()].join('|');
const LEGACY_SYNTAX = new RegExp(
`^(:::(?:${TYPES_PATTERN}))[^\\S\\n]+(?!\\[)(.+?)[^\\S\\n]*$`,
'gm',
);

export function normalizeLegacyAdmonitions(text: string): string {
return text.replace(LEGACY_SYNTAX, '$1[$2]');
}
Comment thread
jgroth marked this conversation as resolved.

export function admonitions(): (tree: Node) => void {
return (tree: Node) => {
visit(tree, 'containerDirective', (node: DirectiveNode) => {
const ifmClass = ADMONITION_TYPES.get(node.name);
if (!ifmClass) {
return;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

const { label, children } = extractLabel(node);
const content = children;

node.data = {
hName: 'div',
hProperties: {
className: [
'admonition',
`admonition-${node.name}`,
'alert',
`alert--${ifmClass}`,
],
},
};

node.children = [
{
type: 'admonitionHeading',
data: {
hName: 'div',
hProperties: { className: ['admonition-heading'] },
},
children: [
{
type: 'admonitionTitle',
data: { hName: 'h5' },
children: [{ type: 'text', value: label }],
},
],
},
{
type: 'admonitionContent',
data: {
hName: 'div',
hProperties: { className: ['admonition-content'] },
},
children: content,
},
];
});
};
}

interface ExtractedLabel {
label: string;
children: Node[];
}

function extractLabel(node: DirectiveNode): ExtractedLabel {
const labelNode = node.children.find(
(child: Node & { data?: Record<string, unknown> }) =>
child.data?.directiveLabel,
);

if (!labelNode || !isParent(labelNode)) {
return { label: node.name, children: node.children };
}

const filtered = node.children.filter((child: Node) => child !== labelNode);

return {
label: extractText(labelNode) || node.name,
children: filtered,
};
}

function extractText(node: Node): string {
if (node.type === 'text') {
return (node as Node & { value: string }).value;
}

if (!isParent(node)) {
return '';
}

return node.children.map(extractText).join('');
}
24 changes: 11 additions & 13 deletions src/kompendium/markdown-code.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import map from 'unist-util-map';
import type { Node } from 'unist';
import { map } from 'unist-util-map';
import { isElement } from './markdown-nodes';

export function kompendiumCode(): (tree) => any {
export function kompendiumCode(): (tree: Node) => Node {
return transformer;
}

function transformer(tree) {
function transformer(tree: Node) {
return map(tree, mapCodeNode);
}

function mapCodeNode(node) {
if (node.type !== 'element') {
function mapCodeNode(node: Node) {
if (!isElement(node)) {
return node;
}

Expand All @@ -29,20 +31,16 @@ function mapCodeNode(node) {
properties: {
language: language,
},
children: [],
};
}

function getLanguage(props: { className?: string[] }) {
if (!props) {
function getLanguage(props?: Record<string, unknown>) {
const className = props?.className;
if (!Array.isArray(className)) {
return;
}

if (!('className' in props)) {
return;
}

const languageClass = props.className.find((name) =>
const languageClass = className.find((name: string) =>
name.startsWith('language-'),
);
if (!languageClass) {
Expand Down
18 changes: 12 additions & 6 deletions src/kompendium/markdown-frontmatter.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import visit from 'unist-util-visit';
import type { Node } from 'unist';
import { visit } from 'unist-util-visit';
import YAML from 'yaml';

export function saveFrontmatter(): (tree, file) => any {
interface VFile {
data: Record<string, unknown>;
}

export function saveFrontmatter(): (tree: Node, file: VFile) => void {
return transformer;
}

function transformer(tree, file) {
return visit(tree, 'yaml', storeData(file));
function transformer(tree: Node, file: VFile) {
visit(tree, 'yaml', storeData(file));
}

const storeData = (file) => (item) => {
file.data.frontmatter = item.data.parsedValue;
const storeData = (file: VFile) => (item: Node & { value?: string }) => {
file.data.frontmatter = item.value ? YAML.parse(item.value) : undefined;
};
23 changes: 23 additions & 0 deletions src/kompendium/markdown-nodes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Node, Parent } from 'unist';

export interface ElementNode extends Parent {
tagName: string;
properties?: Record<string, unknown>;
}

export interface TextNode extends Node {
type: 'text';
value: string;
}

export function isParent(node: Node): node is Parent {
return 'children' in node;
}

export function isTextNode(node: Node): node is TextNode {
return node.type === 'text';
}

export function isElement(node: Node): node is ElementNode {
return node.type === 'element' && 'tagName' in node;
}
95 changes: 84 additions & 11 deletions src/kompendium/markdown-typelinks.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,74 @@
import flatMap from 'unist-util-flatmap';
import type { Node } from 'unist';
import { isElement, isParent, isTextNode } from './markdown-nodes';

export function typeLinks(options: any = {}): (tree) => any {
type MapFn = (node: Node, index: number, parent: Node | null) => Node[];

export function typeLinks(
options: { types?: string[] } = {},
): (tree: Node) => Node {
return transformer(options.types);
}

const transformer =
(types: string[] = []) =>
(tree): any => {
(tree: Node): Node => {
if (types.length === 0) {
return tree;
}

return flatMap(tree, mapCodeNode(types));
const preCodeElements = collectPreCodeElements(tree);

return flatMap(tree, mapCodeNode(types, preCodeElements));
};

function collectPreCodeElements(node: Node): Set<Node> {
const set = new Set<Node>();
collectPreCode(node, set);

return set;
}

function collectPreCode(node: Node, set: Set<Node>) {
if (!isParent(node)) {
return;
}

if (isElement(node) && node.tagName === 'pre') {
for (const child of node.children) {
if (isElement(child) && child.tagName === 'code') {
set.add(child);
}
}
}

for (const child of node.children) {
collectPreCode(child, set);
}
}

const mapCodeNode =
(types: string[] = []) =>
(node, _, parent) => {
if (node.type !== 'text') {
(types: string[] = [], preCodeElements: Set<Node>) =>
(node: Node, _: number, parent: Node | null) => {
if (!isTextNode(node)) {
return [node];
}

if (!parent || !isElement(parent)) {
return [node];
}

if (parent.tagName !== 'code') {
return [node];
}

if (parent.parent?.tagName === 'pre') {
if (preCodeElements.has(parent)) {
return [node];
}

return wrapText(node, types);
};

export function wrapText(node: any, types: string[] = []) {
export function wrapText(node: { value: string }, types: string[] = []) {
return splitTypeString(node.value).map(createNode(types));
}

Expand Down Expand Up @@ -74,15 +110,19 @@ export function splitTypeString(typeString: string): string[] {
const types = typeString.match(pattern);
const result: string[] = [];

if (!types) {
return [typeString];
}

let currentString = typeString;
types.forEach((type: string) => {
const index = currentString.indexOf(type);
if (index > 0) {
result.push(currentString.substr(0, index));
result.push(currentString.substring(0, index));
}

result.push(type);
currentString = currentString.substr(index + type.length);
currentString = currentString.substring(index + type.length);
});

if (currentString.length > 0) {
Expand All @@ -91,3 +131,36 @@ export function splitTypeString(typeString: string): string[] {

return result;
}

function transformChildren(node: Node, fn: MapFn) {
if (!isParent(node)) {
return;
}

node.children = node.children.flatMap((child, i) =>
transform(child, i, node, fn),
);
}

function transform(
node: Node,
index: number,
parent: Node | null,
fn: MapFn,
): Node[] {
transformChildren(node, fn);

return fn(node, index, parent);
}

function flatMap(ast: Node, fn: MapFn): Node {
const result = transform(ast, 0, null, fn);

if (result.length !== 1) {
throw new Error(
`flatMap: root must map to exactly one node, got ${result.length}`,
);
}

return result[0];
}
Loading
Loading