Skip to content

Commit

Permalink
feat: Expose frontmatterNamingConvention option
Browse files Browse the repository at this point in the history
  • Loading branch information
tgreyuk committed Apr 14, 2023
1 parent 557fd70 commit 34f4be2
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 55 deletions.
4 changes: 4 additions & 0 deletions packages/typedoc-plugin-markdown/.markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ MD013: false
# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
MD024: false

# MD025 - Multiple top-level headings in the same document
MD025:
front_matter_title: ''

# MD033/no-inline-html - Inline HTML
MD033: false

Expand Down
2 changes: 2 additions & 0 deletions packages/typedoc-plugin-markdown/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ See [Front matter options](./docs/frontmatter.md) for further documentation.
Specify which file comment tags should be added to front matter variables (as an array).
- **`--frontmatterGlobals`**<br>
Specify global static variables to be added to all front matter blocks (as an object).
- **`--frontmatterNamingConvention`**<br>
Specify the naming convention of front matter variables. Expected values [`camelCase`, `snakeCase`,`kebabCase`]. Defaults to `snakeCase`.

### Utility options

Expand Down
85 changes: 70 additions & 15 deletions packages/typedoc-plugin-markdown/docs/frontmatter.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,67 @@
# Front matter

- [Adding front matter to output](#adding-front-matter-to-output)
- [Setting global variables](#setting-global-variables)
- [Extending front matter with comment tags](#extending-front-matter-with-comment-tags)
- [Front matter variable naming convention](#front-matter-variable-naming-convention)

## Adding front matter to output

The `--enableFrontmatter` option will prepend a simple YAML fron tmatter block to the page containing the page title.
The `--enableFrontmatter` option will prepend a simple YAML front matter block to the page containing the page title.

```
---
title: "someModule"
---
```

## Extending front matter
## Setting global variables

Further front matter variables can be added globally or by using comment tags.
Global variables can be added to all front matter blocks by passing key/values as an object to the `--frontmatterGlobals` option.

### Comment tags
For example, to set `layout` as a global front matter variable would be accomplished by:

Tags added to comment within a [@module tag block](https://typedoc.org/tags/module/) can be marked for exporting to the front matter variables by using the `--frontmatterTags` option.
```shell
--frontmatterGlobals '{\"layout\":\"docs\"}'
```

For example, to mark `author` and description `tags` as fron tmatter would be accomplished by:
or if using JSON config:

```json
{
"frontmatterGlobals": {
"layout": "docs"
}
}
```

Result on each file:

```
---
title: "someModule"
layout: "docs"
---
```

## Extending front matter with comment tags

Further front matter variables can be added globally or by using comment tags.

Tags added to comment blocks within can be marked for exporting to the front matter variables by using the `--frontmatterTags` option.

For example, to mark "author" and "description" tags as front matter would be accomplished by:

```shell
--frontmatterTags author --frontmaterTags description
```

or if using JSON config:

```json
frontMatterTags: ["author","description"]
{
"frontmatterTags": ["author", "description"]
}
```

The following block comment:
Expand All @@ -53,23 +87,44 @@ description: "A description that will be added to front matter."
---
```

### Setting default variables
If tags are not intended to be rendered in the output they should be marked as modifier tags:

Static variables to be added to all front matter blocks can be specified by passing key/values as an object to the `--frontmatterGlobals` option.
```json
{
"modifierTags": ["@author", "@description"]
}
```

The following block comment:
## Front matter variable naming convention

Tag names must be written using “camelCase” capitalization. However this may not be the desired front matter variable naming convention.

To render the front matter variables in the desired naming convention use the `--frontmatterNamingConvention` options that accepts `snakeCase` `kebabCase` or `pascalCase`.

```shell
--frontmatterNamingConvention snakeCase
```
frontmatterGlobals: {
layout: 'docs'

or if using JSON config:

```json
{
"frontmatterNamingConvention": "snakeCase"
}
```

Will result in the following front matter with the defaults added to each block.
The following block comment:

```
/**
* @navOrder 1
**/
```

Will result in the following front matter:

```
---
title: "someModule"
layout: "docs"
nav_order: 1
---
```
2 changes: 1 addition & 1 deletion packages/typedoc-plugin-markdown/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"test": "jest --colors",
"build-and-test": "npm run build && npm run test",
"docs": "npm run build && npm-run-all docs:*",
"docs:md-1": "typedoc --plugin typedoc-plugin-markdown --longTitles --options ../../stubs/typedoc.json --out ./out/md/md-1",
"docs:md-1": "typedoc --plugin typedoc-plugin-markdown --enableFrontmatter --longTitles --options ../../stubs/typedoc.json --out ./out/md/md-1",
"docs:md-2": "typedoc --plugin typedoc-plugin-markdown --groupBySymbols false --hideInPageTOC --typeDeclarationStyle \"list\" --readme \"none\" --symbolsWithOwnFile none --options ../../stubs/typedoc.json --out ./out/md/md-2",
"docs:html": "typedoc --options ../../stubs/typedoc.json --out ./out/html"
},
Expand Down
22 changes: 21 additions & 1 deletion packages/typedoc-plugin-markdown/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,30 @@ export function load(app: Application) {
app.options.addDeclaration({
name: 'frontmatterGlobals',
help: '[Markdown Plugin] Specify static variables to be added to all frontmatter.',
type: ParameterType.Object,
type: ParameterType.Mixed,
defaultValue: {},
});

app.options.addDeclaration({
name: 'frontmatterNamingConvention',
help: '[Markdown Plugin] Specify the naming convention of front matter variables.',
type: ParameterType.String,
defaultValue: 'camelCase',
validate: (option) => {
const availableValues = [
'camelCase',
'snakeCase',
'kebabCase',
'pascalCase',
];
if (!availableValues.includes(option)) {
throw new Error(
`Unexpected value for frontmatterNamingConvention, the expected value is one of 'camelCase', 'snakeCase','kebabCase','pascalCase'`,
);
}
},
});

/**
* Utility options
*/
Expand Down
13 changes: 12 additions & 1 deletion packages/typedoc-plugin-markdown/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export interface TypedocPluginMarkdownOptions extends TypeDocOptionMap {
namedAnchors: boolean;
enableFrontmatter: boolean;
frontmatterTags: string[];
frontmatterGlobals: Record<string, string | boolean | number | null>;
frontmatterGlobals: FrontmatterGlobals;
frontmatterNamingConvention: FrontmatterNamingConvention;
baseUrl: string;
longTitles: boolean;
symbolsWithOwnFile: string | string[];
Expand All @@ -28,3 +29,13 @@ export interface TemplateMapping {
}

export type Collapse = 'object' | 'function' | 'all' | 'none';

export type FrontmatterGlobals =
| string
| Record<string, string | boolean | number | null>;

export type FrontmatterNamingConvention =
| 'camelCase'
| 'snakeCase'
| 'kebabCase'
| 'pascalCase';
102 changes: 90 additions & 12 deletions packages/typedoc-plugin-markdown/src/partials/frontmatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ import {
PageEvent,
ProjectReflection,
} from 'typedoc';
import { getTagName } from '../support/helpers';
import { FrontmatterGlobals, FrontmatterNamingConvention } from '../models';
import { getReflectionTitle, getTagName } from '../support/helpers';
import { stripLineBreaks, unEscapeChars } from '../support/utils';
import { MarkdownThemeRenderContext } from '../theme-context';

export function frontmatter(
context: MarkdownThemeRenderContext,
page: PageEvent<ProjectReflection | DeclarationReflection>,
) {
const globals = context.getOption('frontmatterGlobals');
const yaml = `---\n${Object.entries({
...context.baseFrontmatterVars(page),
...(page.model.comment &&
getFrontmatterTags(
page.model.comment,
context.getOption('frontmatterTags'),
)),
...context.getOption('frontmatterGlobals'),
...getBaseFrontmatterVars(page, context),
...(page.model.comment && getFrontmatterTags(page.model.comment, context)),
...(globals && getGlobals(globals)),
})
.map(
([key, value]) =>
Expand All @@ -28,26 +27,105 @@ export function frontmatter(
return yaml;
}

function getFrontmatterTags(comment: Comment, frontMatterTags: string[]) {
function getBaseFrontmatterVars(
page: PageEvent<ProjectReflection | DeclarationReflection>,
context: MarkdownThemeRenderContext,
) {
return {
[toVariable('title', context.getOption('frontmatterNamingConvention'))]:
unEscapeChars(
getReflectionTitle(
page.model as DeclarationReflection,
context.getOption('longTitles'),
true,
),
),
};
}

function getGlobals(globals: FrontmatterGlobals) {
if (typeof globals === 'string') {
return JSON.parse(globals);
}
return globals;
}

function getFrontmatterTags(
comment: Comment,
context: MarkdownThemeRenderContext,
) {
if (!comment) {
return {};
}

if (comment.blockTags?.length) {
const tags = comment.blockTags
.filter((tag) => frontMatterTags.includes(getTagName(tag)))
.filter((tag) =>
context.getOption('frontmatterTags')?.includes(getTagName(tag)),
)
.reduce((prev, current) => {
const tagName = getTagName(current);
const tagValue = current.content
.filter((commentPart) => commentPart.kind === 'text')
.map((commentPart) => commentPart.text)
.map((commentPart) => stripLineBreaks(commentPart.text, false))
.join('');
return {
...prev,
[tagName]: tagValue,
[toVariable(
tagName,
context.getOption('frontmatterNamingConvention'),
)]: toValue(tagValue),
};
}, {});
return tags;
}
return {};
}

function toValue(tagValue: string) {
return Number(tagValue) || tagValue;
}

function toVariable(
str: string,
namingConvention: FrontmatterNamingConvention,
) {
if (namingConvention === 'snakeCase') {
return toSnakeCase(str);
}
if (namingConvention === 'kebabCase') {
return toKebabCase(str);
}
if (namingConvention === 'pascalCase') {
return toPascalCase(str);
}
return str;
}

function toSnakeCase(str: string) {
return (
str
.match(
/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g,
)
?.map((s) => s.toLowerCase())
.join('_') || ''
);
}

function toPascalCase(str: string) {
return (str.match(/[a-zA-Z0-9]+/g) || [])
.map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`)
.join('');
}

function toKebabCase(str: string) {
return (
str
.match(
/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g,
)
?.join('-')
.toLowerCase() || ''
);
}
8 changes: 6 additions & 2 deletions packages/typedoc-plugin-markdown/src/support/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ export function stripComments(str: string) {
.replace(/^\s+|\s+$|(\s)+/g, '$1');
}

export function stripLineBreaks(str: string) {
export function stripLineBreaks(str: string, includeHTML = true) {
return str
? str.replace(/\n/g, '<br />').replace(/\r/g, '').replace(/\t/g, ' ').trim()
? str
.replace(/\n/g, includeHTML ? '<br />' : ' ')
.replace(/\r/g, '')
.replace(/\t/g, ' ')
.trim()
: '';
}

Expand Down
2 changes: 1 addition & 1 deletion packages/typedoc-plugin-markdown/src/templates/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function projectTemplate(
}

if (page.model.comment) {
md.push(context.partials.comment(page.model.comment, 1));
md.push(context.partials.comment(page.model.comment, 2));
}

md.push(context.partials.toc(page.model));
Expand Down
Loading

0 comments on commit 34f4be2

Please sign in to comment.