chore: reorganize docs apps (#7228)
* reorganize docs apps * add README * fix directory * add condition for old docs
This commit is contained in:
1 parent
224ebb2154
commit
4fe28f5a95
6187 files changed
+601447
-598226
No files matched your search
@@ -0,0 +1,9 @@
|
||||
const path = require("path")
|
||||
|
||||
module.exports = {
|
||||
extends: ["docs"],
|
||||
parserOptions: {
|
||||
project: true,
|
||||
tsconfigRootDir: path.join(__dirname, "..", ".."),
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "remark-rehype-plugins",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"module": "./dist/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"dist/**"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "yarn clean && tsc",
|
||||
"clean": "rimraf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cloudinary/url-gen": "^1.17.0",
|
||||
"remark-frontmatter": "^5.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"to-vfile": "^8.0.0",
|
||||
"unified": "^11.0.4",
|
||||
"unist-builder": "3.0.0",
|
||||
"unist-util-visit": "4.1.2",
|
||||
"vfile-matter": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.20",
|
||||
"docs-ui": "*",
|
||||
"eslint-config-docs": "*",
|
||||
"rimraf": "^5.0.5",
|
||||
"tsconfig": "*",
|
||||
"types": "*",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.17.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { existsSync } from "fs"
|
||||
import path from "path"
|
||||
import type { Transformer } from "unified"
|
||||
import type { UnistNode, UnistTree } from "./types/index.js"
|
||||
|
||||
export function brokenLinkCheckerPlugin(): Transformer {
|
||||
return async (tree, file) => {
|
||||
const { visit } = await import("unist-util-visit")
|
||||
|
||||
const currentPageFilePath = file.history[0].replace(
|
||||
`/${path.basename(file.history[0])}`,
|
||||
""
|
||||
)
|
||||
|
||||
visit(tree as UnistTree, "element", (node: UnistNode) => {
|
||||
if (node.tagName !== "a" || !node.properties?.href?.match(/page\.mdx?/)) {
|
||||
return
|
||||
}
|
||||
// get absolute path of the URL
|
||||
const linkedFilePath = path
|
||||
.resolve(currentPageFilePath, node.properties.href)
|
||||
.replace(/#.*$/, "")
|
||||
// check if the file exists
|
||||
if (!existsSync(linkedFilePath)) {
|
||||
throw new Error(
|
||||
`Broken link found! ${node.properties.href} linked in ${file.history[0]}`
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import type { Transformer } from "unified"
|
||||
import type { CloudinaryConfig, UnistNode, UnistTree } from "./types/index.js"
|
||||
|
||||
const cloudinaryImageRegex =
|
||||
/^https:\/\/res.cloudinary.com\/.*\/upload\/v[0-9]+\/(?<imageId>.*)$/
|
||||
|
||||
export function cloudinaryImgRehypePlugin({
|
||||
cloudinaryConfig,
|
||||
}: {
|
||||
cloudinaryConfig: CloudinaryConfig
|
||||
}): Transformer {
|
||||
return async (tree) => {
|
||||
if (!cloudinaryConfig) {
|
||||
return
|
||||
}
|
||||
const { visit } = await import("unist-util-visit")
|
||||
const { Cloudinary } = await import("@cloudinary/url-gen")
|
||||
const { byRadius } = await import(
|
||||
"@cloudinary/url-gen/actions/roundCorners"
|
||||
)
|
||||
|
||||
const {
|
||||
pad,
|
||||
imaggaScale,
|
||||
imaggaCrop,
|
||||
crop,
|
||||
fit,
|
||||
minimumPad,
|
||||
fill,
|
||||
scale,
|
||||
limitFit,
|
||||
thumbnail,
|
||||
limitFill,
|
||||
minimumFit,
|
||||
limitPad,
|
||||
fillPad,
|
||||
} = await import("@cloudinary/url-gen/actions/resize")
|
||||
|
||||
const resizeActions = {
|
||||
pad,
|
||||
imaggaScale,
|
||||
imaggaCrop,
|
||||
crop,
|
||||
fit,
|
||||
minimumPad,
|
||||
fill,
|
||||
scale,
|
||||
limitFit,
|
||||
thumbnail,
|
||||
limitFill,
|
||||
minimumFit,
|
||||
limitPad,
|
||||
fillPad,
|
||||
}
|
||||
|
||||
visit(tree as UnistTree, (node: UnistNode) => {
|
||||
const matchingRegex = node.properties?.src?.match(cloudinaryImageRegex)
|
||||
|
||||
if (node.tagName !== "img" || !matchingRegex?.groups?.imageId) {
|
||||
return
|
||||
}
|
||||
|
||||
const cloudinary = new Cloudinary({
|
||||
cloud: {
|
||||
cloudName: cloudinaryConfig.cloudName,
|
||||
},
|
||||
})
|
||||
const image = cloudinary.image(
|
||||
matchingRegex.groups.imageId.replaceAll("%20", " ")
|
||||
)
|
||||
|
||||
cloudinaryConfig.flags?.forEach((flag) => image.addTransformation(flag))
|
||||
|
||||
if (cloudinaryConfig.roundCorners) {
|
||||
image.roundCorners(byRadius(cloudinaryConfig.roundCorners))
|
||||
}
|
||||
|
||||
if (cloudinaryConfig.resize) {
|
||||
const action =
|
||||
resizeActions[
|
||||
cloudinaryConfig.resize.action as keyof typeof resizeActions
|
||||
]
|
||||
let resizeAction = action()
|
||||
if (node.properties?.width || node.properties?.height) {
|
||||
if (node.properties?.width) {
|
||||
resizeAction = resizeAction.width(node.properties.width)
|
||||
}
|
||||
|
||||
if (node.properties?.height) {
|
||||
resizeAction = resizeAction.height(node.properties.height)
|
||||
}
|
||||
} else if (cloudinaryConfig.resize.aspectRatio) {
|
||||
resizeAction = resizeAction.aspectRatio(
|
||||
cloudinaryConfig.resize.aspectRatio
|
||||
)
|
||||
} else {
|
||||
if (cloudinaryConfig.resize.width) {
|
||||
resizeAction = resizeAction.width(cloudinaryConfig.resize.width)
|
||||
}
|
||||
|
||||
if (cloudinaryConfig.resize.height) {
|
||||
resizeAction = resizeAction.height(cloudinaryConfig.resize.height)
|
||||
}
|
||||
}
|
||||
|
||||
image.resize(resizeAction)
|
||||
}
|
||||
|
||||
node.properties!.src = image.toURL()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { Transformer } from "unified"
|
||||
import type {
|
||||
CrossProjectLinksOptions,
|
||||
UnistNode,
|
||||
UnistTree,
|
||||
} from "./types/index.js"
|
||||
|
||||
const PROJECT_REGEX = /^!(?<area>[\w-]+)!/
|
||||
|
||||
export function crossProjectLinksPlugin({
|
||||
baseUrl,
|
||||
projectUrls,
|
||||
}: CrossProjectLinksOptions): Transformer {
|
||||
return async (tree) => {
|
||||
const { visit } = await import("unist-util-visit")
|
||||
visit(tree as UnistTree, "element", (node: UnistNode) => {
|
||||
if (node.tagName !== "a" || !node.properties?.href) {
|
||||
return
|
||||
}
|
||||
|
||||
const projectArea = PROJECT_REGEX.exec(node.properties.href)
|
||||
|
||||
if (!projectArea?.groups?.area) {
|
||||
return
|
||||
}
|
||||
|
||||
const actualUrl = node.properties.href.replace(PROJECT_REGEX, "")
|
||||
|
||||
const base =
|
||||
projectUrls &&
|
||||
Object.hasOwn(projectUrls, projectArea.groups.area) &&
|
||||
projectUrls[projectArea.groups.area]?.url
|
||||
? projectUrls[projectArea.groups.area].url
|
||||
: baseUrl
|
||||
const path =
|
||||
projectUrls &&
|
||||
Object.hasOwn(projectUrls, projectArea.groups.area) &&
|
||||
projectUrls[projectArea.groups.area]?.path
|
||||
? projectUrls[projectArea.groups.area].path
|
||||
: projectArea.groups.area
|
||||
|
||||
node.properties.href = `${base}/${path}${actualUrl}`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export * from "./broken-link-checker.js"
|
||||
export * from "./cloudinary-img.js"
|
||||
export * from "./cross-project-links.js"
|
||||
export * from "./local-links.js"
|
||||
export * from "./page-number.js"
|
||||
export * from "./resolve-admonitions.js"
|
||||
export * from "./type-list-link-fixer.js"
|
||||
|
||||
export * from "./utils/fix-link.js"
|
||||
export * from "./utils/get-file-slug.js"
|
||||
export * from "./utils/get-front-matter.js"
|
||||
@@ -0,0 +1,40 @@
|
||||
import path from "path"
|
||||
import type { Transformer } from "unified"
|
||||
import type { LocalLinkOptions, UnistNode, UnistTree } from "./types/index.js"
|
||||
import { fixLinkUtil } from "./index.js"
|
||||
|
||||
export function localLinksRehypePlugin(options: LocalLinkOptions): Transformer {
|
||||
const { filePath, basePath } = options || {}
|
||||
return async (tree, file) => {
|
||||
if (!file.cwd) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!file.history.length) {
|
||||
if (!filePath) {
|
||||
return
|
||||
}
|
||||
|
||||
file.history.push(filePath)
|
||||
}
|
||||
|
||||
const { visit } = await import("unist-util-visit")
|
||||
|
||||
const currentPageFilePath = file.history[0].replace(
|
||||
`/${path.basename(file.history[0])}`,
|
||||
""
|
||||
)
|
||||
const appsPath = basePath || path.join(file.cwd, "app")
|
||||
visit(tree as UnistTree, "element", (node: UnistNode) => {
|
||||
if (node.tagName !== "a" || !node.properties?.href?.match(/page\.mdx?/)) {
|
||||
return
|
||||
}
|
||||
|
||||
node.properties.href = fixLinkUtil({
|
||||
currentPageFilePath,
|
||||
linkedPath: node.properties.href,
|
||||
appsPath,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import path from "path"
|
||||
import type { Transformer } from "unified"
|
||||
import type { RawSidebarItemType } from "types"
|
||||
import type { UnistTree } from "./types/index.js"
|
||||
|
||||
export function pageNumberRehypePlugin({
|
||||
sidebar,
|
||||
}: {
|
||||
sidebar: RawSidebarItemType[]
|
||||
}): Transformer {
|
||||
return async (tree, file) => {
|
||||
const { valueToEstree } = await import("estree-util-value-to-estree")
|
||||
let number = ""
|
||||
|
||||
if (file.history.length) {
|
||||
// get page path
|
||||
const pageFilePath = file.history[0].replace(
|
||||
path.join(file.cwd, "app"),
|
||||
""
|
||||
)
|
||||
let pagePath = pageFilePath.replace(`/${path.basename(pageFilePath)}`, "")
|
||||
|
||||
if (!pagePath.length) {
|
||||
pagePath = "/"
|
||||
}
|
||||
|
||||
const pageSidebarItem = findSidebarItem(sidebar, pagePath)
|
||||
|
||||
if (pageSidebarItem?.number) {
|
||||
number = pageSidebarItem?.number
|
||||
}
|
||||
}
|
||||
|
||||
;(tree as UnistTree).children.unshift({
|
||||
type: "mdxjsEsm",
|
||||
value: `export const pageNumber = "${number}"`,
|
||||
data: {
|
||||
estree: {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "ExportNamedDeclaration",
|
||||
declaration: {
|
||||
type: "VariableDeclaration",
|
||||
declarations: [
|
||||
{
|
||||
type: "VariableDeclarator",
|
||||
id: {
|
||||
type: "Identifier",
|
||||
name: "pageNumber",
|
||||
},
|
||||
init: valueToEstree(number),
|
||||
},
|
||||
],
|
||||
kind: "const",
|
||||
},
|
||||
specifiers: [],
|
||||
source: null,
|
||||
},
|
||||
],
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function findSidebarItem(
|
||||
sidebar: RawSidebarItemType[],
|
||||
path: string
|
||||
): RawSidebarItemType | undefined {
|
||||
let foundItem = undefined
|
||||
for (const item of sidebar) {
|
||||
if (path === item.path) {
|
||||
foundItem = item
|
||||
} else if (item.children) {
|
||||
foundItem = findSidebarItem(item.children, path)
|
||||
}
|
||||
|
||||
if (foundItem) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return foundItem
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Transformer } from "unified"
|
||||
import { UnistNode } from "./types/index.js"
|
||||
|
||||
const ALLOWED_NODE_NAMES = ["note", "tip", "info", "warning"]
|
||||
|
||||
export function resolveAdmonitionsPlugin(): Transformer {
|
||||
return async (tree) => {
|
||||
const { visit } = await import("unist-util-visit")
|
||||
visit(tree as UnistNode, (node: UnistNode) => {
|
||||
if (
|
||||
(node.type !== "containerDirective" &&
|
||||
node.type !== "leafDirective" &&
|
||||
node.type !== "textDirective") ||
|
||||
!node.name ||
|
||||
!ALLOWED_NODE_NAMES.includes(node.name)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
let title: string | undefined
|
||||
node.children?.some((childNode, childIndex) => {
|
||||
if (childNode.data?.directiveLabel && childNode.children?.length) {
|
||||
title = childNode.children.find((item) => item.type === "text")?.value
|
||||
|
||||
if (title) {
|
||||
node.children?.splice(childIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return title !== undefined
|
||||
})
|
||||
|
||||
if (!node.data) {
|
||||
node.data = {}
|
||||
}
|
||||
|
||||
node.data.hName = "Note"
|
||||
node.data.hProperties = {
|
||||
title:
|
||||
title ||
|
||||
(node.name !== "note"
|
||||
? `${node.name.charAt(0).toUpperCase()}${node.name.substring(1)}`
|
||||
: "Note"),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import path from "path"
|
||||
import { Transformer } from "unified"
|
||||
import {
|
||||
TypeListLinkFixerOptions,
|
||||
UnistNode,
|
||||
UnistNodeWithData,
|
||||
UnistTree,
|
||||
} from "./types/index.js"
|
||||
import { FixLinkOptions, fixLinkUtil } from "./index.js"
|
||||
|
||||
const LINK_REGEX = /\[(.*?)\]\((?<link>.*?)\)/gm
|
||||
|
||||
function matchLinks(
|
||||
str: string,
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">
|
||||
) {
|
||||
let linkMatches
|
||||
while ((linkMatches = LINK_REGEX.exec(str)) !== null) {
|
||||
if (!linkMatches.groups?.link) {
|
||||
return
|
||||
}
|
||||
|
||||
const newUrl = fixLinkUtil({
|
||||
...linkOptions,
|
||||
linkedPath: linkMatches.groups.link,
|
||||
})
|
||||
|
||||
str = str.replace(linkMatches.groups.link, newUrl)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
function traverseTypes(
|
||||
types: Record<string, unknown>[],
|
||||
linkOptions: Omit<FixLinkOptions, "linkedPath">
|
||||
) {
|
||||
return types.map((typeItem) => {
|
||||
typeItem.type = matchLinks(typeItem.type as string, linkOptions)
|
||||
typeItem.description = matchLinks(
|
||||
typeItem.description as string,
|
||||
linkOptions
|
||||
)
|
||||
if (typeItem.children) {
|
||||
typeItem.children = traverseTypes(
|
||||
typeItem.children as Record<string, unknown>[],
|
||||
linkOptions
|
||||
)
|
||||
}
|
||||
|
||||
return typeItem
|
||||
})
|
||||
}
|
||||
|
||||
export function typeListLinkFixerPlugin(
|
||||
options?: TypeListLinkFixerOptions
|
||||
): Transformer {
|
||||
const { filePath, basePath } = options || {}
|
||||
return async (tree, file) => {
|
||||
if (!file.cwd) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!file.history.length) {
|
||||
if (!filePath) {
|
||||
return
|
||||
}
|
||||
|
||||
file.history.push(filePath)
|
||||
}
|
||||
|
||||
const { visit } = await import("unist-util-visit")
|
||||
|
||||
const currentPageFilePath = file.history[0].replace(
|
||||
`/${path.basename(file.history[0])}`,
|
||||
""
|
||||
)
|
||||
const appsPath = basePath || path.join(file.cwd, "app")
|
||||
visit(tree as UnistTree, "mdxJsxFlowElement", (node: UnistNode) => {
|
||||
if (node.name !== "TypeList") {
|
||||
return
|
||||
}
|
||||
|
||||
const typesAttributeIndex = node.attributes?.findIndex(
|
||||
(attribute) => attribute.name === "types"
|
||||
)
|
||||
if (typesAttributeIndex === undefined || typesAttributeIndex === -1) {
|
||||
return
|
||||
}
|
||||
const typesAttribute = node.attributes![typesAttributeIndex]
|
||||
|
||||
if (
|
||||
!typesAttribute ||
|
||||
!(typesAttribute.value as Record<string, unknown>)?.value
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const linkOptions = {
|
||||
currentPageFilePath,
|
||||
appsPath,
|
||||
}
|
||||
|
||||
let newItems: Record<string, unknown>[]
|
||||
|
||||
try {
|
||||
newItems = traverseTypes(
|
||||
JSON.parse(
|
||||
(typesAttribute.value as Record<string, unknown>).value as string
|
||||
) as Record<string, unknown>[],
|
||||
linkOptions
|
||||
)
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`[type-list-link-fixer-plugin]: An error occurred while parsing items for page ${file.history[0]}: ${e}`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
;(
|
||||
node.attributes![typesAttributeIndex].value as Record<string, unknown>
|
||||
).value = JSON.stringify(newItems)
|
||||
|
||||
if (
|
||||
(node as UnistNodeWithData).attributes![typesAttributeIndex].value?.data
|
||||
?.estree?.body?.length
|
||||
) {
|
||||
const oldItems = (node as UnistNodeWithData).attributes[
|
||||
typesAttributeIndex
|
||||
].value.data!.estree!.body![0].expression!.elements!
|
||||
|
||||
;(node as UnistNodeWithData).attributes[
|
||||
typesAttributeIndex
|
||||
].value.data!.estree!.body![0].expression!.elements = newItems.map(
|
||||
(newItem, index) => {
|
||||
oldItems[index].properties = oldItems[index].properties.map(
|
||||
(property) => {
|
||||
if (Object.hasOwn(newItem, property.key.value)) {
|
||||
property.value.value = newItem[property.key.value]
|
||||
property.value.raw = JSON.stringify(
|
||||
newItem[property.key.value]
|
||||
)
|
||||
}
|
||||
|
||||
return property
|
||||
}
|
||||
)
|
||||
|
||||
return oldItems[index]
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Node } from "unist-builder"
|
||||
|
||||
export interface UnistNode extends Node {
|
||||
type: string
|
||||
name?: string
|
||||
tagName?: string
|
||||
value?: string
|
||||
properties?: {
|
||||
[key: string]: string
|
||||
}
|
||||
attributes?: {
|
||||
name: string
|
||||
value: unknown
|
||||
type?: string
|
||||
}[]
|
||||
children?: UnistNode[]
|
||||
}
|
||||
|
||||
export interface UnistNodeWithData extends UnistNode {
|
||||
attributes: {
|
||||
name: string
|
||||
value: {
|
||||
data?: {
|
||||
estree?: {
|
||||
body?: {
|
||||
type?: string
|
||||
expression?: {
|
||||
type?: string
|
||||
elements?: {
|
||||
properties: AttributeProperty[]
|
||||
}[]
|
||||
}
|
||||
}[]
|
||||
}
|
||||
}
|
||||
value?: string
|
||||
}
|
||||
type?: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface AttributeProperty {
|
||||
key: {
|
||||
value: string
|
||||
raw: string
|
||||
}
|
||||
value: {
|
||||
value: unknown
|
||||
raw: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface UnistTree extends Node {
|
||||
children: UnistNode[]
|
||||
}
|
||||
|
||||
export declare type CloudinaryConfig = {
|
||||
cloudName?: string
|
||||
flags?: string[]
|
||||
resize?: {
|
||||
action: string
|
||||
width?: number
|
||||
height?: number
|
||||
aspectRatio?: string
|
||||
}
|
||||
roundCorners?: number
|
||||
}
|
||||
|
||||
export declare type FrontMatter = {
|
||||
slug?: string
|
||||
sidebar_label?: string
|
||||
sidebar_group?: string
|
||||
sidebar_group_main?: boolean
|
||||
sidebar_position?: number
|
||||
sidebar_autogenerate_exclude?: boolean
|
||||
}
|
||||
|
||||
export declare type CrossProjectLinksOptions = {
|
||||
baseUrl: string
|
||||
projectUrls?: {
|
||||
[k: string]: {
|
||||
url: string
|
||||
path?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export declare type TypeListLinkFixerOptions = {
|
||||
filePath?: string
|
||||
basePath?: string
|
||||
}
|
||||
|
||||
export declare type LocalLinkOptions = {
|
||||
filePath?: string
|
||||
basePath?: string
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import path from "path"
|
||||
|
||||
export type FixLinkOptions = {
|
||||
currentPageFilePath: string
|
||||
linkedPath: string
|
||||
appsPath: string
|
||||
}
|
||||
|
||||
export function fixLinkUtil({
|
||||
currentPageFilePath,
|
||||
linkedPath,
|
||||
appsPath: basePath,
|
||||
}: FixLinkOptions) {
|
||||
// get absolute path of the URL
|
||||
const linkedFilePath = path
|
||||
.resolve(currentPageFilePath, linkedPath)
|
||||
.replace(basePath, "")
|
||||
// persist hash in new URL
|
||||
const hash = linkedFilePath.includes("#")
|
||||
? linkedFilePath.substring(linkedFilePath.indexOf("#"))
|
||||
: ""
|
||||
|
||||
return `${linkedFilePath.substring(
|
||||
0,
|
||||
linkedFilePath.indexOf(`/${path.basename(linkedFilePath)}`)
|
||||
)}${hash}`
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { getFrontMatterUtil } from "./get-front-matter.js"
|
||||
|
||||
export async function getFileSlugUtil(
|
||||
filePath: string
|
||||
): Promise<string | undefined> {
|
||||
const fileFrontmatter = await getFrontMatterUtil(filePath)
|
||||
|
||||
if (fileFrontmatter.slug) {
|
||||
// add to slugs array
|
||||
return fileFrontmatter.slug
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import remarkFrontmatter from "remark-frontmatter"
|
||||
import remarkParse from "remark-parse"
|
||||
import remarkStringify from "remark-stringify"
|
||||
import { unified } from "unified"
|
||||
import { read } from "to-vfile"
|
||||
import { matter } from "vfile-matter"
|
||||
import { FrontMatter } from "../types/index.js"
|
||||
|
||||
export async function getFrontMatterUtil(
|
||||
filePath: string
|
||||
): Promise<FrontMatter> {
|
||||
return (
|
||||
await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkStringify)
|
||||
.use(remarkFrontmatter, ["yaml"])
|
||||
.use(() => {
|
||||
return (tree, file) => {
|
||||
matter(file)
|
||||
}
|
||||
})
|
||||
.process(await read(filePath))
|
||||
).data.matter as FrontMatter
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": ["tsconfig/base.json"],
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"tsBuildInfoFile": "./dist/.tsbuildinfo-client",
|
||||
"noEmit": false,
|
||||
"lib": ["es2022"],
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in new issue
Block a user