@xyd-js/content 0.1.0-xyd.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,172 @@
1
+ import {promises as fs} from 'fs';
2
+ import fs2, {open} from 'fs';
3
+ import path from 'path';
4
+
5
+ import React from "react";
6
+ import remarkFrontmatter from "remark-frontmatter";
7
+ import remarkMdxFrontmatter from "remark-mdx-frontmatter";
8
+ import matter from 'gray-matter';
9
+ import {VFile} from "vfile";
10
+ import {compile as mdxCompile} from "@mdx-js/mdx";
11
+
12
+ import {FrontMatter, Sidebar, PageFrontMatter, Header} from "@xyd-js/core";
13
+
14
+ // TODO: better algorithm + data structures - since it's on build time it's not a big deal nevertheless it should be changed in the future
15
+
16
+ // pageFrontMatters gets frontmatters for given navigation
17
+ export async function pageFrontMatters(navigation: Sidebar[]): Promise<PageFrontMatter> {
18
+ const frontmatters: PageFrontMatter = {}
19
+
20
+ const promises: Promise<any>[] = []
21
+
22
+ function mapPages(page: string | Sidebar) {
23
+ if (typeof page !== "string") {
24
+ page.pages?.forEach(mapPages)
25
+ return
26
+ }
27
+
28
+ promises.push(job(page, frontmatters))
29
+ }
30
+
31
+ navigation.map(async (nav: Sidebar) => {
32
+ nav.pages?.forEach(mapPages)
33
+ })
34
+
35
+ await Promise.all(promises)
36
+
37
+ return frontmatters
38
+ }
39
+
40
+ // filterNavigation filter navigation items by top levels of 'header' configuration and current 'slug'
41
+ export function filterNavigationByLevels(
42
+ headers: Header[],
43
+ slug: string
44
+ ) {
45
+ const topLevelTabMatcher = headers?.reduce((acc: any, header) => {
46
+ const tabLevel = header?.url?.split("/")?.length
47
+
48
+ if (!tabLevel) {
49
+ return {
50
+ ...acc
51
+ }
52
+ }
53
+
54
+ if (!acc[tabLevel]) {
55
+ return {
56
+ ...acc,
57
+ [tabLevel]: new Set().add(header?.url)
58
+ }
59
+ }
60
+
61
+ return {
62
+ ...acc,
63
+ [tabLevel]: acc[tabLevel].add(header?.url)
64
+ }
65
+ }, {}) as { [level: number]: Set<string> }
66
+
67
+ return (nav: Sidebar) => {
68
+ let match = false
69
+
70
+ Object.keys(topLevelTabMatcher).forEach((levelStr) => {
71
+ if (match) {
72
+ return true
73
+ }
74
+ const level = parseInt(levelStr)
75
+ const findThisSlug = slug.split("/").filter(s => !!s).slice(0, level).join("/")
76
+
77
+ function findMatchedPage(page: string | Sidebar) {
78
+ if (typeof page !== "string") {
79
+ page.pages?.forEach(findMatchedPage)
80
+ return
81
+ }
82
+ const findThisPage = page.split("/").filter(p => !!p).slice(0, level).join("/")
83
+
84
+ const set = topLevelTabMatcher[level]
85
+
86
+ if (set.has(findThisPage) && findThisPage === findThisSlug) {
87
+ match = true
88
+ return true
89
+ }
90
+ }
91
+
92
+ nav?.pages?.forEach(findMatchedPage)
93
+ })
94
+
95
+ return match
96
+ }
97
+ }
98
+
99
+ function mdxExport(code: string) {
100
+ const scope = {
101
+ Fragment: React.Fragment,
102
+ jsxs: React.createElement,
103
+ jsx: React.createElement,
104
+ jsxDEV: React.createElement,
105
+ }
106
+ const fn = new Function(...Object.keys(scope), code)
107
+ return fn(scope)
108
+ }
109
+
110
+ async function getFrontmatter(filePath: string): Promise<FrontMatter> {
111
+ const body = await fs.readFile(filePath, "utf-8");
112
+
113
+ const vfile = new VFile({
114
+ path: filePath,
115
+ value: body,
116
+ contents: body
117
+ });
118
+
119
+ const compiled = await mdxCompile(vfile, {
120
+ remarkPlugins: [
121
+ remarkFrontmatter,
122
+ remarkMdxFrontmatter
123
+ ],
124
+ rehypePlugins: [],
125
+ recmaPlugins: [],
126
+ outputFormat: 'function-body',
127
+ development: false,
128
+ });
129
+
130
+ const code = String(compiled)
131
+
132
+ const {
133
+ reactFrontmatter, // in the future same key?
134
+ frontmatter
135
+ } = mdxExport(code)
136
+
137
+ const matter: FrontMatter = frontmatter
138
+
139
+ let title = ""
140
+ if (typeof matter.title === "string" ) {
141
+ title = matter.title
142
+ }
143
+ if (reactFrontmatter) {
144
+ if (typeof reactFrontmatter?.title === "function") {
145
+ matter.title = {
146
+ title,
147
+ code: reactFrontmatter.title.toString()
148
+ }
149
+ }
150
+ }
151
+
152
+ return matter
153
+ }
154
+
155
+ async function job(page: string, frontmatters: PageFrontMatter) {
156
+ // TODO: it can be cwd because on build time it has entire path?
157
+ let filePath = path.join(process.cwd(), `${page}.mdx`) // TODO: support md toos
158
+ try {
159
+ await fs.access(filePath)
160
+ } catch (e) {
161
+ try {
162
+ const mdPath = filePath.replace(".mdx", ".md")
163
+ await fs.access(mdPath)
164
+ filePath = mdPath
165
+ } catch (e) {
166
+ }
167
+ }
168
+
169
+ const matter = await getFrontmatter(filePath)
170
+
171
+ frontmatters[page] = matter
172
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "paths": {
5
+ "@/mdx/*": ["src/mdx/*"],
6
+ "@/navigation/*": ["src/navigation/*"],
7
+ "@/utils/*": ["src/utils/*"],
8
+ "@/vite-plugins/*": ["src/vite-plugins/*"]
9
+ },
10
+ "target": "ES2020",
11
+ "module": "ESNext",
12
+ "moduleResolution": "node",
13
+ "strict": true,
14
+ "esModuleInterop": true,
15
+ "skipLibCheck": true,
16
+ "forceConsistentCasingInFileNames": true,
17
+ "outDir": "./dist",
18
+ "types": ["node", "estree", "vite"],
19
+ "declaration": true,
20
+ "declarationMap": true,
21
+ "incremental": true,
22
+ "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
23
+ },
24
+ "include": ["src/**/*.ts"],
25
+ "exclude": ["node_modules", "dist"]
26
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,29 @@
1
+ import {defineConfig, Options} from 'tsup';
2
+
3
+ const config: Options = {
4
+ entry: {
5
+ index: 'src/index.ts',
6
+ vite: 'packages/vite/index.ts',
7
+ md: 'packages/md/index.ts',
8
+ },
9
+ dts: {
10
+ entry: {
11
+ index: 'src/index.ts',
12
+ vite: 'packages/vite/index.ts',
13
+ md: 'packages/md/index.ts'
14
+ },
15
+ resolve: true, // Resolve external types
16
+ },
17
+ format: ['esm'], // Output both ESM and CJS formats
18
+ target: 'node16', // Ensure compatibility with Node.js 16
19
+ splitting: false, // Disable code splitting
20
+ sourcemap: true, // Generate source maps
21
+ clean: true, // Clean the output directory before each build
22
+ // esbuildOptions: (options) => {
23
+ // options.platform = 'node'; // Ensure the platform is set to Node.js
24
+ // options.external = ['node:fs/promises']; // Mark 'node:fs/promises' as external
25
+ // options.loader = { '.js': 'jsx' }; // Ensure proper handling of .js files
26
+ // },
27
+ };
28
+
29
+ export default defineConfig(config);