Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Commit 187ba88

Browse files
committed
added anchors to content data FIXES #13
1 parent 31a6248 commit 187ba88

File tree

5 files changed

+90
-79
lines changed

5 files changed

+90
-79
lines changed

lib/content/page.js

Lines changed: 56 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,26 @@ const paramCase = require('param-case')
66
const permalinkCompiler = require('path-to-regexp').compile
77

88
export default function prepPage (meta, options) {
9+
const source = readFileSync(meta.filePath).toString()
910
const cached = {}
1011

11-
return { // TODO include permalink and anchors and is data injected?
12+
return { // TODO is data injected?
1213
create () {
13-
const { permalink, date, data, template } = this
14+
const { date, permalink, anchors, data } = this
1415
return {
1516
meta,
16-
permalink,
1717
date,
18+
permalink,
19+
anchors,
1820
...data,
1921
}
2022
},
2123

22-
get data () {
23-
if (!cached.data) { // TODO inject additional data
24-
cached.data = parseFile(meta, options)
25-
}
26-
return cached.data
27-
},
28-
2924
get permalink () {
3025
if (!cached.permalink) {
31-
const { date, slug, section } = this
26+
const { date } = this
27+
const { section, fileName } = meta
28+
const slug = getSlug(fileName)
3229
const { year, month, day } = splitDate(date)
3330
const params = { section, slug, date, year, month, day }
3431
const toPermalink = permalinkCompiler(options.permalink)
@@ -39,6 +36,49 @@ export default function prepPage (meta, options) {
3936
return cached.permalink
4037
},
4138

39+
get anchors () {
40+
if (!cached.anchors) {
41+
const level = options.anchorsLevel
42+
const anchorsExp = new RegExp(`(#{${level + 1},})|#{${level}}(.*)`, 'g')
43+
let result
44+
let anchors = []
45+
while (result = anchorsExp.exec(source)) {
46+
let [match, otherLevel, capturedHeading] = result
47+
if (!otherLevel && capturedHeading) {
48+
const anchor = `#${paramCase(capturedHeading)}`
49+
anchors.push([anchor, capturedHeading])
50+
}
51+
}
52+
cached.anchors = anchors
53+
}
54+
return cached.anchors
55+
},
56+
57+
get data () {
58+
if (!cached.data) {
59+
const { fileName } = meta
60+
const { parsers } = options
61+
if (fileName.search(/\.comp\.md$/) > -1) {
62+
const { attributes } = fm(source)
63+
const { dirName, section, fileName } = meta
64+
const relativePath = '.' + join(dirName, section, fileName)
65+
cached.data = {
66+
...attributes,
67+
body: { relativePath } // component body compiled by loader and imported separately
68+
}
69+
} else if (fileName.search(/\.md$/) > -1) {
70+
const { attributes, body } = fm(source)
71+
cached.data = {
72+
...attributes,
73+
body: parsers.mdParser(parsers.md, options).render(body)
74+
}
75+
} else if (fileName.search(/\.yaml$/) > -1) {
76+
cached.data = parsers.yamlParser().render(source)
77+
}
78+
}
79+
return cached.data
80+
},
81+
4282
get date () {
4383
if (!cached.date) {
4484
const { filePath, fileName, section } = meta
@@ -52,49 +92,15 @@ export default function prepPage (meta, options) {
5292
}
5393
}
5494
return cached.date
55-
},
56-
57-
get slug () {
58-
if (!cached.slug) {
59-
const { fileName } = meta
60-
const onlyName = fileName
61-
.replace(/(\.comp)?(\.[0-9a-z]+$)/, '') // remove any ext
62-
.replace(/!?(\d{4}-\d{2}-\d{2}-)/, '') // remove date and hypen
63-
cached.slug = paramCase(onlyName)
64-
}
65-
return cached.slug
66-
},
67-
68-
get section () {
69-
return meta.section
7095
}
7196
}
7297
}
7398

74-
75-
76-
function parseFile(meta, options) {
77-
const { filePath, fileName } = meta
78-
const source = readFileSync(filePath).toString()
79-
if (fileName.search(/\.md/) > -1) return compileMd(source, meta, options)
80-
else if (fileName.search(/\.yaml/) > -1) return options.parsers.yaml(source)
81-
}
82-
83-
function compileMd(source, { dirName, section, fileName }, { parsers }) {
84-
const { attributes, body } = fm(source)
85-
if (fileName.search(/\.comp\.md/) > -1) {
86-
const relativePath = '.' + join(dirName, section, fileName)
87-
return {
88-
...attributes,
89-
// component body is compiled by loader and imported seperately
90-
body: { relativePath }
91-
}
92-
} else {
93-
return {
94-
...attributes,
95-
body: parsers.md.render(body)
96-
}
97-
}
99+
function getSlug (fileName) {
100+
const onlyName = fileName
101+
.replace(/(\.comp)?(\.[0-9a-z]+$)/, '') // remove any ext
102+
.replace(/!?(\d{4}-\d{2}-\d{2}-)/, '') // remove date and hypen
103+
return paramCase(onlyName)
98104
}
99105

100106
function splitDate (date) {

lib/loader.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ const mdCompParser = (mdParser) => {
1616
return parser
1717
}
1818

19-
const mdComponent = (source, { srcPath, sitePath, componentsDir, parsers }) => {
19+
const mdComponent = (source, moduleOpts, dirOpts) => {
20+
const { srcPath, sitePath, componentsDir, parsers } = moduleOpts
2021
// captures code or markdown component -- '@[]' or '@[]()'
2122
const compExp = /(`{3}[a-z]*\n[\s\S]*?\n`{3})|(`{1}.*?`{1})|@\[(.*?)\](?:\((.*?)\))?/g
2223
let result
@@ -34,19 +35,23 @@ const mdComponent = (source, { srcPath, sitePath, componentsDir, parsers }) => {
3435
}
3536
}
3637

38+
const { mdParser, md } = parsers
39+
3740
return {
38-
template: mdCompParser(parsers.md).render(source),
41+
template: mdCompParser(parsers.mdParser(md, dirOpts)).render(source),
3942
components: comps
4043
}
4144
}
4245

4346
module.exports = function (source) {
4447
this.cacheable()
4548

46-
const options = loaderUtils.getOptions(this)
49+
const moduleOpts = loaderUtils.getOptions(this)
50+
const section = getSection(this.context)
51+
const dirOpts = moduleOpts.content[section]
4752

4853
const { body } = fm(source)
49-
const { template, components } = mdComponent(body, options)
54+
const { template, components } = mdComponent(body, moduleOpts, dirOpts)
5055

5156
const allImports = Object.keys(components)
5257
.map(key => `import ${key} from '~components/${components[key]}'`).join('\n')
@@ -85,6 +90,11 @@ function mergeParserRules (parser, rules, fn) {
8590
return parser
8691
}
8792

93+
function getSection (path) {
94+
const [match, section] = path.match(/\/content([\/].*|$)/)
95+
return section === '' ? '/' : section
96+
}
97+
8898
function getExt(basePath, name) {
8999
if (existsSync(basePath + name + '.vue')) return '.vue'
90100
else if (existsSync(basePath + name + '.js')) return '.js'

lib/module.js

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import createRouter from './content/api'
22
import interceptRoutes from './content/routes'
33
import buildContent from './content/build'
4-
import parsers from './util/parsers'
4+
import { mdParser, yamlParser } from './util/parsers'
55

66
const { existsSync } = require('fs')
77
const { resolve, join } = require('path')
@@ -30,14 +30,6 @@ const contentOptions = (content, defaults) => {
3030
return opts
3131
}
3232

33-
const contentParsers = (opts, defaults) => {
34-
const options = { ...defaults, ...opts }
35-
return {
36-
md: parsers.md(options.md),
37-
yaml: parsers.yaml
38-
}
39-
}
40-
4133
const apiOptions = (opts, defaults, isProd) => {
4234
const baseURL = opts && opts.baseURL ? opts.baseURL(isProd) : defaults.baseURL
4335
return { baseURL }
@@ -57,22 +49,20 @@ export default function ContentModule(moduleOpts) {
5749
content: contentOptions(userOptions.content, {
5850
routeName: null,
5951
permalink: ':slug',
52+
anchorsLevel: 1,
6053
isPost: true,
6154
data: {}
6255
}),
6356

64-
parsers: contentParsers(userOptions.parser, {
57+
parsers: {
6558
md: {
6659
highlight: null,
67-
use: [],
68-
options: {
69-
anchors: {
70-
level: 1,
71-
permalinkClass: 'nuxtent-anchor'
72-
}
73-
}
74-
}
75-
}),
60+
use: []
61+
},
62+
...userOptions.parsers,
63+
mdParser,
64+
yamlParser
65+
},
7666

7767
api: {
7868
...apiOptions(userOptions.api, {
@@ -83,6 +73,7 @@ export default function ContentModule(moduleOpts) {
8373
}
8474
}
8575

76+
8677
const { isDev, srcDir, content, api } = options
8778

8879
// 1. Configure and build dynamic content pages

lib/util/parsers.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
const yamlParser = require('js-yaml')
1+
const yamlit = require('js-yaml')
22
const markdownit = require('markdown-it')
33
const markdownAnchors = require('markdown-it-anchor')
44

5-
const mdParser = ({ highlight, use, options }) => {
5+
export const mdParser = ({ highlight, use }, { anchorsLevel }) => {
66
const parser = markdownit({
77
preset: 'default',
88
html: true,
@@ -12,7 +12,9 @@ const mdParser = ({ highlight, use, options }) => {
1212
})
1313

1414
const plugins = [
15-
[markdownAnchors, options.anchors]
15+
[markdownAnchors, { // TODO they are all getting IDs! :(
16+
level: anchorsLevel
17+
}]
1618
].concat(use)
1719

1820
plugins.forEach(plugin => {
@@ -22,7 +24,8 @@ const mdParser = ({ highlight, use, options }) => {
2224
return parser
2325
}
2426

25-
export default {
26-
md: mdParser,
27-
yaml: yamlParser.safeLoad
27+
export const yamlParser = () => {
28+
return {
29+
render: yamlit.safeLoad
30+
}
2831
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"js-yaml": "^3.9.0",
3939
"loader-utils": "^1.1.0",
4040
"markdown-it": "^8.3.1",
41+
"markdown-it-anchor": "^4.0.0",
4142
"moment": "^2.18.1",
4243
"param-case": "^2.1.1",
4344
"path-to-regexp": "^1.7.0",

0 commit comments

Comments
 (0)