1 | const { basename, dirname, join, relative, resolve } = require('path')
|
2 | const R = require('ramda')
|
3 | const FileUtil = require('./file')
|
4 | const { crossPlatformPath, titleize } = require('./string')
|
5 | const { UiengineInputError } = require('./error')
|
6 |
|
7 | const INDEX_FILE_PATH = '.'
|
8 | const INDEX_PAGE_PATH = ''
|
9 | const PAGE_CONFNAME = 'page.config.js'
|
10 | const PAGE_DOCSNAME = 'README.md'
|
11 | const INDEX_ID = 'index'
|
12 |
|
13 |
|
14 | const PAGE_TYPE_TOKENS = 'tokens'
|
15 | const PAGE_TYPE_TEMPLATE = 'template'
|
16 | const PAGE_TYPE_DOCUMENTATION = 'documentation'
|
17 |
|
18 | const isIndexPage = pageId =>
|
19 | pageId === INDEX_ID
|
20 |
|
21 | const isIndexFilePath = pagePath =>
|
22 | pagePath === INDEX_FILE_PATH
|
23 |
|
24 | const isIndexPagePath = pagePath =>
|
25 | pagePath === INDEX_PAGE_PATH
|
26 |
|
27 | const isDocumentationPage = pageType =>
|
28 | pageType === PAGE_TYPE_DOCUMENTATION
|
29 |
|
30 | const isTokensPage = pageType =>
|
31 | pageType === PAGE_TYPE_TOKENS
|
32 |
|
33 | const pageIdToPath = pageId =>
|
34 | isIndexPage(pageId) ? INDEX_PAGE_PATH : pageId
|
35 |
|
36 | const pageIdForComponentId = (parentPageId, componentId) =>
|
37 | isIndexPage(parentPageId) ? componentId : `${pageIdToPath(parentPageId)}/${componentId}`
|
38 |
|
39 | const pagePathForComponentId = (parentPagePath, componentId) =>
|
40 | isIndexPagePath(parentPagePath) ? componentId : `${parentPagePath}/${componentId}`
|
41 |
|
42 | const pageIdToTitle = pageId => {
|
43 | if (isIndexPage(pageId)) return 'Home'
|
44 |
|
45 | const base = basename(pageId)
|
46 | const title = titleize(base)
|
47 |
|
48 | return title
|
49 | }
|
50 |
|
51 | const pageIdToFilePath = (pagesPath, pageId, fileName = PAGE_CONFNAME) => {
|
52 | const relativePath = isIndexPage(pageId) ? INDEX_FILE_PATH : pageId
|
53 | const absolutePath = join(pagesPath, relativePath, fileName)
|
54 |
|
55 | return absolutePath
|
56 | }
|
57 |
|
58 | const pageFilePathToId = (pagesPath, filePath) => {
|
59 | const relativePath = relative(pagesPath, filePath)
|
60 |
|
61 |
|
62 | if (relativePath.startsWith('..')) return null
|
63 |
|
64 | const dir = dirname(relativePath)
|
65 | const file = basename(relativePath)
|
66 | const isPageFile = file === PAGE_CONFNAME || file === PAGE_DOCSNAME
|
67 |
|
68 | if (isPageFile || FileUtil.exists(resolve(filePath, '..', PAGE_CONFNAME)) || FileUtil.exists(resolve(filePath, '..', PAGE_DOCSNAME))) {
|
69 | const pageId = isIndexFilePath(dir) ? INDEX_ID : crossPlatformPath(dir)
|
70 |
|
71 | return pageId
|
72 | } else {
|
73 | const parentPath = resolve(filePath, '..', '..')
|
74 | const parentFilePath = join(parentPath, file)
|
75 |
|
76 | return pageFilePathToId(pagesPath, parentFilePath)
|
77 | }
|
78 | }
|
79 |
|
80 | const parentIdForPageId = (pageIds, pageId) => {
|
81 | if (isIndexPage(pageId)) return null
|
82 | const parentDir = dirname(pageId)
|
83 | const parentId = isIndexFilePath(parentDir) ? INDEX_ID : parentDir
|
84 |
|
85 | return pageIds.includes(parentId)
|
86 | ? parentId
|
87 | : parentIdForPageId(pageIds, parentId)
|
88 | }
|
89 |
|
90 | const determineType = attributes => {
|
91 | if (attributes.tokens) {
|
92 | return PAGE_TYPE_TOKENS
|
93 | } else if (attributes.template || attributes.fragment) {
|
94 | return PAGE_TYPE_TEMPLATE
|
95 | } else {
|
96 | return PAGE_TYPE_DOCUMENTATION
|
97 | }
|
98 | }
|
99 |
|
100 |
|
101 |
|
102 | const convertUserProvidedChildrenList = (pageId, availableChildIds, attributes) => {
|
103 | const { children } = attributes
|
104 | if (!(children instanceof Array)) return attributes
|
105 |
|
106 | const prefix = pageIdToPath(pageId)
|
107 | const childIds = R.map(id => {
|
108 | const childId = id.startsWith(prefix) ? id : `${prefix}/${id}`
|
109 | if (availableChildIds.includes(childId)) {
|
110 | return childId
|
111 | } else {
|
112 | throw new UiengineInputError([
|
113 | `Child page "${id}" does not exist for page "${pageId}".`,
|
114 | 'Here is a list of available child pages:',
|
115 | availableChildIds.map(childId => `- ${childId}`).join('\n')
|
116 | ])
|
117 | }
|
118 | }, children)
|
119 |
|
120 | attributes = R.dissoc('children', attributes)
|
121 | attributes = R.assoc('childIds', childIds, attributes)
|
122 |
|
123 | return attributes
|
124 | }
|
125 |
|
126 |
|
127 |
|
128 | const convertUserProvidedComponentsList = (pageId, attributes) => {
|
129 | const { components } = attributes
|
130 | if (typeof components !== 'object') return attributes
|
131 |
|
132 | attributes = R.dissoc('components', attributes)
|
133 | attributes = R.assoc('componentIds', components, attributes)
|
134 |
|
135 | return attributes
|
136 | }
|
137 |
|
138 | module.exports = {
|
139 | PAGE_CONFNAME,
|
140 | PAGE_DOCSNAME,
|
141 | INDEX_ID,
|
142 | convertUserProvidedChildrenList,
|
143 | convertUserProvidedComponentsList,
|
144 | isIndexPage,
|
145 | isIndexFilePath,
|
146 | isIndexPagePath,
|
147 | isDocumentationPage,
|
148 | isTokensPage,
|
149 | determineType,
|
150 | pageIdToPath,
|
151 | pageIdForComponentId,
|
152 | pagePathForComponentId,
|
153 | pageIdToTitle,
|
154 | pageIdToFilePath,
|
155 | pageFilePathToId,
|
156 | parentIdForPageId
|
157 | }
|