UNPKG

4.53 kBJavaScriptView Raw
1const fs = require('fs')
2const { join } = require('path')
3const fm = require('front-matter')
4const pathToRegexp = require('path-to-regexp')
5const paramCase = require('param-case')
6
7const parser = require('markdown-it')({
8 preset: 'default',
9 html: true
10 // highlight: renderHighlight
11})
12
13var contentData = {}
14
15/**
16 * Returns 2D array of content data. The data is nested under its
17 * registered directory.
18 */
19exports.default = function getContent (options) {
20 const srcPath = join(options.srcPath, options.srcDir)
21
22 const registeredDirs = !Array.isArray(options.dirs[0])
23 ? [[options.dirs[0]]] : options.dirs
24
25 registeredDirs.forEach(type => {
26 const dirName = join('/', type[0])
27 const dirOpts = getDirOpts(type[1] || {}, options)
28 const otherDirs = getOtherRegisteredDirs(dirName, registeredDirs)
29 contentData[dirName] = []
30 getFromDir(srcPath, dirName, otherDirs, dirOpts)
31 })
32 return contentData
33}
34
35exports.getContent = function (onlyDir) {
36 return contentData
37}
38
39
40/**
41 * Initiates fecthing of pages from specified directory.
42 */
43function getFromDir(srcPath, registeredDir, blacklist, dirOpts) {
44 /**
45 * Recursively gets all content files nested under registered directory.
46 */
47 function applyToAllFiles (dir, func, files = []) {
48 const dirPath = join(srcPath, registeredDir, dir)
49 fs.readdirSync(dirPath).forEach(stat => {
50 const statPath = join(dirPath, stat)
51 if(fs.statSync(statPath).isDirectory()) {
52 const nestedDir = join(dir, stat)
53 getFilesData(nestedDir, func, files)
54 } else {
55 const nestedfilePath = join(dir, stat)
56 func(nestedfilePath)
57 }
58 })
59 return files
60 }
61
62 const dirPath = join(srcPath, registeredDir)
63 fs.readdirSync(dirPath).forEach(stat => {
64 const statPath = join(dirPath, stat)
65 if(fs.statSync(statPath).isDirectory()) { // Nested Files
66 const dirSection = join(registeredDir, stat)
67 if (!(blacklist.indexOf(dirSection) > -1)) {
68 applyToAllFiles(stat, nestedFilePath => {
69 const filePath = join(dirPath, nestedFilePath)
70 contentData[registeredDir].push({
71 src: nestedFilePath,
72 data: getPageData(filePath, registeredDir, dirOpts)
73 })
74 })
75 }
76 } else { // Top Level files
77 contentData[registeredDir].push({
78 src: stat,
79 data: getPageData(statPath, registeredDir, dirOpts)
80 })
81 }
82 })
83
84 return contentData
85}
86
87
88/**
89 * Gets all required page data.
90 *
91 * Data is retrieved either via 1) front-matter 2) file name 3) config options.
92 */
93function getPageData(filePath, section, dirOpts) {
94 function getUrlData (metadata) {
95 const urlData = {}
96
97 urlData.fileName = filePath
98 .replace(/^.*[\\\/]/, '') // remove path
99 .replace(/(.)[^.]+$/, '') // remove ext
100
101 urlData.section = section
102
103 urlData.slug = paramCase(metadata.slug
104 || urlData.fileName.replace(/!?(\d{4}-\d{2}-\d{2}-)/, '')) // remove date
105
106 if (dirOpts.isPost) {
107 const fileDate = urlData.fileName.match(/!?(\d{4}-\d{2}-\d{2})/) // YYYY-MM-DD
108 if (!fileDate) throw Error(`Content in "${section}" does not have a date!`)
109
110 urlData.date = fileDate[0]
111
112 const dateData = urlData.date.split('-')
113 urlData.year = dateData[0]
114 urlData.month = dateData[1]
115 urlData.day = dateData[2]
116 }
117
118 const toPath = pathToRegexp.compile(dirOpts.permalink)
119 urlData.permalink = metadata.permalink
120 || toPath(urlData, { pretty: true }).replace(/%2F/gi, "/") // make url encoded slash pretty
121
122 return urlData
123 }
124
125 const source = fs.readFileSync(filePath, 'utf-8')
126 const frontMatter = fm(source)
127
128 const metadata = frontMatter.attributes
129 const urlData = getUrlData(metadata, dirOpts)
130 const markdown = frontMatter.body
131
132 const data = Object.assign({}, urlData, metadata, {
133 content: parser.render(markdown) // md -> html
134 })
135
136 return data
137}
138
139/**
140 * Gets content options via 1) directory options 2) global content config.
141 */
142function getDirOpts (dir, config) {
143 const mergedData = Object.assign({}, config.data, dir.data)
144 const opts = Object.assign({}, config, dir, { data: mergedData })
145
146 return {
147 permalink: opts.permalink,
148 isPost: !(opts.isPost === false),
149 data: opts.data
150 }
151}
152
153/**
154 * Gets all the registered content directory types.
155 */
156function getOtherRegisteredDirs (currDir, contentTypes) {
157 const dirs = []
158 contentTypes.forEach(type => {
159 const dir = type[0]
160 if (dir !== currDir) dirs.push(join('/' + dir))
161 })
162 return dirs
163}