Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MarkdownPlugin populates route property #20

Merged
merged 7 commits into from
Mar 21, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
introduce IHeadingTag extends ITag with route & level
to make rendering headings really easy.
Compiler turns all `@#+` tags into `tag: "heading"`, but can't populate `route` yet.
Page operates on "page" and "heading" tags (so readable!).
  • Loading branch information
Gilad Gray committed Mar 20, 2017
commit 6244f696aa0f6855d0a5ba3eb6f9c8331cdf0033
34 changes: 31 additions & 3 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { StringOrTag } from "./plugins/plugin";
/**
* Copyright 2017-present Palantir Technologies, Inc. All rights reserved.
* Licensed under the BSD-3 License as modified (the “License”); you may obtain
Expand All @@ -7,16 +8,43 @@

/** Represents a single `@tag <value>` line from a file. */
export interface ITag {
/** Tag name. */
tag: string;
/** Tag value, exactly as written in source. */
value: string;
}

/**
* Represents a single `@#+ <value>` heading tag from a file. Note that all `@#+` tags
* (`@#` through `@######`) are emitted as `tag: "heading"` so only one renderer is necessary to
* capture all six levels.
*
* Heading tags include additional information over regular tags: fully-qualified `route` of the
* heading (which can be used as anchor `href`), and `level` to determine which `<h#>` tag to use.
*/
export interface IHeadingTag extends ITag {
tag: "heading";
/** Fully-qualified route of the heading, which can be used as anchor `href`. */
route: string;
/** Level of heading, from 1-6. Dictates which `<h#>` tag to render. */
level: number;
}

/** An entry in `contents` array: either an HTML string or an `@tag`. */
export type StringOrTag = string | ITag;

/** type guard to determine if a `contents` node is an `@tag` statement */
export function isTag(node: StringOrTag): node is ITag {
return (node as ITag).tag !== undefined;
/**
* Type guard to determine if a `contents` node is an `@tag` statement.
* Optionally tests tag name too, if `tagName` arg is provided.
*/
export function isTag(node: StringOrTag, tagName?: string): node is ITag {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handy!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep very proud of this

return node != null && (node as ITag).tag !== undefined
&& (tagName === undefined || (node as ITag).tag === tagName);
}

/** Type guard to deterimine if a `contents` node is an `@#+` heading tag. */
export function isHeadingTag(node: StringOrTag): node is IHeadingTag {
return isTag(node, "heading");
}

/**
Expand Down
12 changes: 8 additions & 4 deletions src/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as yaml from "js-yaml";
import * as marked from "marked";

import { IHeadingTag } from "./client";
import { IBlock, ICompiler, StringOrTag } from "./plugins/plugin";

/**
Expand Down Expand Up @@ -81,11 +82,14 @@ export class Compiler implements ICompiler {
const match = TAG_REGEX.exec(str);
if (match === null || reservedWords.indexOf(match[1]) >= 0) {
return str;
}
const tag = match[1];
const value = match[2];
if (/#+/.test(tag)) {
// NOTE: not enough information to populate `route` field yet
return { level: tag.length, tag: "heading", value } as IHeadingTag;
} else {
return {
tag: match[1],
value: match[2],
};
return { tag, value };
}
});
}
Expand Down
20 changes: 9 additions & 11 deletions src/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import * as path from "path";
import { IHeadingNode, IPageData, IPageNode, isTag, slugify } from "./client";
import { IHeadingNode, IPageData, IPageNode, isHeadingTag, isTag, slugify } from "./client";

export type PartialPageData = Pick<IPageData, "absolutePath" | "contentRaw" | "contents" | "metadata">;

Expand Down Expand Up @@ -68,15 +68,13 @@ export class PageMap {
throw new Error(`Unknown @page '${id}' in toTree()`);
}
const pageNode = initPageNode(page, depth);
page.contents.forEach((node, i) => {
page.contents.forEach((node) => {
// we only care about @page and @#+ tag nodes
if (isTag(node)) {
if (node.tag === "page") {
pageNode.children.push(this.toTree(node.value, depth + 1));
} else if (i > 0 && node.tag.match(/^#+$/)) {
// use heading strength - 1 cuz h1 is the title
pageNode.children.push(initHeadingNode(node.value, pageNode.depth + node.tag.length - 1));
}
if (isTag(node, "page")) {
pageNode.children.push(this.toTree(node.value, depth + 1));
} else if (isHeadingTag(node) && node.level > 1) {
// use heading strength - 1 cuz h1 is the title
pageNode.children.push(initHeadingNode(node.value, pageNode.depth + node.level - 1));
}
});
return pageNode;
Expand Down Expand Up @@ -104,8 +102,8 @@ function getTitle(data: PartialPageData) {
}

const first = data.contents[0];
if (isTag(first) && first.tag.match(/^#+$/)) {
return first.value as string;
if (isHeadingTag(first)) {
return first.value;
}

return "(untitled)";
Expand Down