add-class.ts 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. // See: https://github.com/martypdx/rehype-add-classes for the original implementation.
  2. // Re-implemeted in TypeScript.
  3. import type { Element, Nodes as HastNode, Properties } from 'hast';
  4. import { selectAll } from 'hast-util-select';
  5. import type { Plugin } from 'unified';
  6. export type SelectorName = string; // e.g. 'h1'
  7. export type ClassName = string; // e.g. 'header'
  8. export type Additions = Record<SelectorName, ClassName>;
  9. export type AdditionsEntry = [SelectorName, ClassName];
  10. export const addClassToProperties = (
  11. properties: Properties | undefined,
  12. className: string,
  13. ): void => {
  14. if (properties == null) {
  15. return;
  16. }
  17. if (properties.className == null) {
  18. properties.className = className;
  19. return;
  20. }
  21. if (Array.isArray(properties.className)) {
  22. properties.className.push(className);
  23. return;
  24. }
  25. properties.className += ` ${className}`;
  26. };
  27. const generateWriter = (className: string) => (element: Element) => {
  28. const { properties } = element;
  29. addClassToProperties(properties, className);
  30. };
  31. const adder = (entry: AdditionsEntry) => {
  32. const [selectorName, className] = entry;
  33. const writer = generateWriter(className);
  34. return (node: HastNode) => selectAll(selectorName, node).forEach(writer);
  35. };
  36. export const rehypePlugin: Plugin<[Additions]> = (additions) => {
  37. const adders = Object.entries(additions).map(adder);
  38. return (node) => {
  39. adders.forEach((a) => {
  40. a(node as HastNode);
  41. });
  42. };
  43. };