From 9bb4d3fd7efb1b219e878597c7949d50ecd04b2b Mon Sep 17 00:00:00 2001 From: Billie Hilton Date: Mon, 16 May 2022 14:08:16 -0700 Subject: [PATCH] feat: getTitle supports raw strings now (#77) --- src/getters/__tests__/get-title.test.ts | 101 ++++++++++++++++++------ src/getters/get-title.ts | 28 ++++++- 2 files changed, 102 insertions(+), 27 deletions(-) diff --git a/src/getters/__tests__/get-title.test.ts b/src/getters/__tests__/get-title.test.ts index b26f5ce..bb691cb 100644 --- a/src/getters/__tests__/get-title.test.ts +++ b/src/getters/__tests__/get-title.test.ts @@ -1,52 +1,103 @@ import { parse } from '../../parse'; import { getTitle } from '../get-title'; -describe('get-title', () => { - it('should return frontmatter title if present', () => { - const title = getTitle( - parse(`--- +const titleInFrontMatter = `--- title: hello --- # Other Title Yo -`), - ); - - expect(title).toBe('hello'); - }); +`; - it('should return heading if present', () => { - const title = getTitle( - parse(`--- +const titleInH1 = `--- summary: what it is about --- # Other Title Yo -`), - ); +`; - expect(title).toBe('Other Title'); - }); +const titleInUnderlineH1 = `--- +summary: what it is about +--- + +Other Title +=========== - it('should return headings other than h1 if present', () => { - const title = getTitle( - parse(`what it is about +Yo +`; + +const titleInH2 = `what it is about ## Other Title 2 Yo -`), - ); +`; + +const noTitle = `what it is about`; + +describe('get-title', () => { + describe('parsed', () => { + it('should return frontmatter title if present', () => { + const title = getTitle(parse(titleInFrontMatter)); + + expect(title).toBe('hello'); + }); + + it('should return # heading if present', () => { + const title = getTitle(parse(titleInH1)); - expect(title).toBe('Other Title 2'); + expect(title).toBe('Other Title'); + }); + + it('should return underlined heading if present', () => { + const title = getTitle(parse(titleInUnderlineH1)); + + expect(title).toBe('Other Title'); + }); + + it('should return headings other than h1 if present', () => { + const title = getTitle(parse(titleInH2)); + + expect(title).toBe('Other Title 2'); + }); + + it('should return undefined if no frontmatter title and no headings', () => { + const title = getTitle(parse(noTitle)); + expect(title).toBe(undefined); + }); }); - it('should return undefined if no frontmatter title and no headings', () => { - const title = getTitle(parse(`what it is about`)); - expect(title).toBe(undefined); + describe('raw string', () => { + it('should return frontmatter title if present', () => { + const title = getTitle(titleInFrontMatter); + + expect(title).toBe('hello'); + }); + + it('should return # heading if present', () => { + const title = getTitle(titleInH1); + + expect(title).toBe('Other Title'); + }); + + it('should not detect underlined headings, sorry not sorry', () => { + const title = getTitle(titleInUnderlineH1); + + expect(title).toBe(undefined); + }); + + it('should return headings other than h1 if present', () => { + const title = getTitle(titleInH2); + + expect(title).toBe('Other Title 2'); + }); + + it('should return undefined if no frontmatter title and no headings', () => { + const title = getTitle(noTitle); + expect(title).toBe(undefined); + }); }); }); diff --git a/src/getters/get-title.ts b/src/getters/get-title.ts index 606321d..dca0271 100644 --- a/src/getters/get-title.ts +++ b/src/getters/get-title.ts @@ -1,7 +1,31 @@ import { MDAST } from '../ast-types'; +import { Frontmatter } from '../frontmatter'; import { getProperty } from './get-property'; // Priority: yaml title, then first heading -export const getTitle = (data?: MDAST.Root) => { - return getProperty('title', 'heading', data); +export const getTitle = (data?: MDAST.Root | string) => { + if (typeof data === 'string') { + return getTitleFromRaw(data); + } else { + return getProperty('title', 'heading', data); + } }; + +function getTitleFromRaw(raw?: string) { + if (!raw) return raw; + + const frontmatterBlock = Frontmatter.getFrontmatterBlock(raw); + + if (frontmatterBlock) { + const title = new Frontmatter(frontmatterBlock).get('title'); + if (title) { + return String(title); + } + } + + // Note: This only supports #-style headings, but underlined headings are much rarer + // Sonar Cloud flagged the original version /^#+\s*(.*)$/m as super-linear, so it has + // become this rather nasty regex to emulate atomic groups / possessive qualifiers. + const match = raw?.match(/^(?=(#+))\1(?=(\s*))\2(?=(.*))\3$/m); + return match ? match[3] : void 0; +}