From 2f6747b1666316e579c6e7238092ac6a65d00925 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Wed, 16 Aug 2023 22:04:15 -0700 Subject: [PATCH] fix relative path resolution in router and link crawling --- content/features/upcoming features.md | 2 - content/hosting.md | 5 +- package-lock.json | 10 --- package.json | 3 +- quartz/bootstrap-cli.mjs | 74 +++++++++++++++---- quartz/build.ts | 12 +-- quartz/components/Backlinks.tsx | 2 +- quartz/components/Head.tsx | 4 +- quartz/components/PageList.tsx | 2 +- quartz/components/PageTitle.tsx | 2 +- quartz/components/TagList.tsx | 2 +- quartz/components/pages/FolderContent.tsx | 2 +- quartz/components/pages/TagContent.tsx | 2 +- quartz/components/renderPage.tsx | 4 +- quartz/components/scripts/graph.inline.ts | 2 +- quartz/components/scripts/search.inline.ts | 2 +- quartz/components/scripts/spa.inline.ts | 2 +- quartz/plugins/emitters/aliases.ts | 2 +- quartz/plugins/emitters/assets.ts | 4 +- quartz/plugins/emitters/componentResources.ts | 8 +- quartz/plugins/emitters/contentIndex.ts | 8 +- quartz/plugins/emitters/contentPage.tsx | 2 +- quartz/plugins/emitters/folderPage.tsx | 8 +- quartz/plugins/emitters/static.ts | 4 +- quartz/plugins/emitters/tagPage.tsx | 4 +- quartz/plugins/index.ts | 6 +- quartz/plugins/transformers/frontmatter.ts | 2 +- quartz/plugins/transformers/links.ts | 2 +- quartz/plugins/transformers/ofm.ts | 6 +- quartz/plugins/types.ts | 6 +- quartz/processors/emit.ts | 10 +-- quartz/processors/filter.ts | 4 +- quartz/processors/parse.ts | 10 +-- quartz/{ => util}/ctx.ts | 2 +- quartz/{ => util}/glob.ts | 0 quartz/{ => util}/log.ts | 0 quartz/{ => util}/path.test.ts | 27 ++++--- quartz/{ => util}/path.ts | 17 +++-- quartz/{ => util}/perf.ts | 0 quartz/{ => util}/resources.tsx | 0 quartz/{ => util}/sourcemap.ts | 0 quartz/{ => util}/theme.ts | 0 quartz/{ => util}/trace.ts | 0 quartz/worker.ts | 2 +- 44 files changed, 160 insertions(+), 106 deletions(-) rename quartz/{ => util}/ctx.ts (87%) rename quartz/{ => util}/glob.ts (100%) rename quartz/{ => util}/log.ts (100%) rename quartz/{ => util}/path.test.ts (96%) rename quartz/{ => util}/path.ts (96%) rename quartz/{ => util}/perf.ts (100%) rename quartz/{ => util}/resources.tsx (100%) rename quartz/{ => util}/sourcemap.ts (100%) rename quartz/{ => util}/theme.ts (100%) rename quartz/{ => util}/trace.ts (100%) diff --git a/content/features/upcoming features.md b/content/features/upcoming features.md index 6c64f18bc..8d6c657b4 100644 --- a/content/features/upcoming features.md +++ b/content/features/upcoming features.md @@ -8,8 +8,6 @@ draft: true - debounce cfg rebuild on large repos - investigate content rebuild triggering multiple times even when debounced, causing an esbuild deadlock - dereference symlink for npx quartz sync -- test/fix with subpath -- fix docs with deploy from github ## high priority backlog diff --git a/content/hosting.md b/content/hosting.md index 5cab7601d..11dff1822 100644 --- a/content/hosting.md +++ b/content/hosting.md @@ -80,7 +80,10 @@ jobs: uses: actions/deploy-pages@v2 ``` -Then, commit these changes by doing `npx quartz sync`. This should deploy your site to `.github.io/`. +Then: + +1. Head to "Settings" tab of your forked repository and in the sidebar, click "Pages". Under "Source", select "GitHub Actions". +2. Commit these changes by doing `npx quartz sync`. This should deploy your site to `.github.io/`. ### Custom Domain diff --git a/package-lock.json b/package-lock.json index f8eb5a424..4245d6184 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,6 @@ "@types/js-yaml": "^4.0.5", "@types/node": "^20.1.2", "@types/pretty-time": "^1.1.2", - "@types/serve-handler": "^6.1.1", "@types/source-map-support": "^0.5.6", "@types/workerpool": "^6.4.0", "@types/ws": "^8.5.5", @@ -1478,15 +1477,6 @@ "integrity": "sha512-4i+Y+O5H80Rh01lY/3Z0hB/UWc4R64ReE83joEpVsIG3iQWpYx66k6pQh1amJNZquKtJQyu/RcfkTtvL0KwssA==", "dev": true }, - "node_modules/@types/serve-handler": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@types/serve-handler/-/serve-handler-6.1.1.tgz", - "integrity": "sha512-bIwSmD+OV8w0t2e7EWsuQYlGoS1o5aEdVktgkXaa43Zm0qVWi21xaSRb3DQA1UXD+DJ5bRq1Rgu14ZczB+CjIQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/source-map-support": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/@types/source-map-support/-/source-map-support-0.5.6.tgz", diff --git a/package.json b/package.json index 29b46f206..17e46b06f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "scripts": { "check": "tsc --noEmit && npx prettier . --check", "format": "npx prettier . --write", - "test": "tsx ./quartz/path.test.ts", + "test": "tsx ./quartz/util/path.test.ts", "profile": "0x -D prof ./quartz/bootstrap-cli.mjs build --concurrency=1" }, "keywords": [ @@ -89,7 +89,6 @@ "@types/js-yaml": "^4.0.5", "@types/node": "^20.1.2", "@types/pretty-time": "^1.1.2", - "@types/serve-handler": "^6.1.1", "@types/source-map-support": "^0.5.6", "@types/workerpool": "^6.4.0", "@types/ws": "^8.5.5", diff --git a/quartz/bootstrap-cli.mjs b/quartz/bootstrap-cli.mjs index 0730f907f..077e31b13 100755 --- a/quartz/bootstrap-cli.mjs +++ b/quartz/bootstrap-cli.mjs @@ -74,6 +74,10 @@ const BuildArgv = { default: false, describe: "run a local server to live-preview your Quartz", }, + baseDir: { + string: true, + describe: "base path to serve your local server on", + }, port: { number: true, default: 8080, @@ -384,19 +388,63 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. await build(clientRefresh) const server = http.createServer(async (req, res) => { - await serveHandler(req, res, { - public: argv.output, - directoryListing: false, - trailingSlash: true, - }) - const status = res.statusCode - const statusString = - status >= 200 && status < 300 - ? chalk.green(`[${status}]`) - : status >= 300 && status < 400 - ? chalk.yellow(`[${status}]`) - : chalk.red(`[${status}]`) - console.log(statusString + chalk.grey(` ${req.url}`)) + const serve = async (fp) => { + await serveHandler(req, res, { + public: argv.output, + directoryListing: false, + }) + const status = res.statusCode + const statusString = + status >= 200 && status < 300 ? chalk.green(`[${status}]`) : chalk.red(`[${status}]`) + console.log(statusString + chalk.grey(` ${req.url}`)) + } + + const redirect = (newFp) => { + res.writeHead(301, { + Location: newFp, + }) + console.log(chalk.yellow("[301]") + chalk.grey(` ${req.url} -> ${newFp}`)) + return res.end() + } + + let fp = req.url?.split("?")[0] ?? "/" + + // handle redirects + if (fp.endsWith("/")) { + // /trailing/ + // does /trailing/index.html exist? if so, serve it + const indexFp = path.posix.join(fp, "index.html") + if (fs.existsSync(path.posix.join(argv.output, indexFp))) { + return serve(indexFp) + } + + // does /trailing.html exist? if so, redirect to /trailing + let base = fp.slice(0, -1) + if (path.extname(base) === "") { + base += ".html" + } + if (fs.existsSync(path.posix.join(argv.output, base))) { + return redirect(base) + } + } else { + // /regular + // does /regular.html exist? if so, serve it + let base = fp + if (path.extname(base) === "") { + base += ".html" + } + if (fs.existsSync(path.posix.join(argv.output, base))) { + return serve(base) + } + + // does /regular/index.html exist? if so, redirect to /regular/ + let indexFp = path.posix.join(fp, "index.html") + if (fs.existsSync(path.posix.join(argv.output, indexFp))) { + return redirect(fp + "/") + } + } + + return serve(fp) }) server.listen(argv.port) console.log(chalk.cyan(`Started a Quartz server listening at http://localhost:${argv.port}`)) diff --git a/quartz/build.ts b/quartz/build.ts index c25efbf43..779ab35eb 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -1,7 +1,7 @@ import sourceMapSupport from "source-map-support" sourceMapSupport.install(options) import path from "path" -import { PerfTimer } from "./perf" +import { PerfTimer } from "./util/perf" import { rimraf } from "rimraf" import { isGitIgnored } from "globby" import chalk from "chalk" @@ -9,13 +9,13 @@ import { parseMarkdown } from "./processors/parse" import { filterContent } from "./processors/filter" import { emitContent } from "./processors/emit" import cfg from "../quartz.config" -import { FilePath, joinSegments, slugifyFilePath } from "./path" +import { FilePath, joinSegments, slugifyFilePath } from "./util/path" import chokidar from "chokidar" import { ProcessedContent } from "./plugins/vfile" -import { Argv, BuildCtx } from "./ctx" -import { glob, toPosixPath } from "./glob" -import { trace } from "./trace" -import { options } from "./sourcemap" +import { Argv, BuildCtx } from "./util/ctx" +import { glob, toPosixPath } from "./util/glob" +import { trace } from "./util/trace" +import { options } from "./util/sourcemap" async function buildQuartz(argv: Argv, clientRefresh: () => void) { const ctx: BuildCtx = { diff --git a/quartz/components/Backlinks.tsx b/quartz/components/Backlinks.tsx index 575e61339..8cf3afa2f 100644 --- a/quartz/components/Backlinks.tsx +++ b/quartz/components/Backlinks.tsx @@ -1,6 +1,6 @@ import { QuartzComponentConstructor, QuartzComponentProps } from "./types" import style from "./styles/backlinks.scss" -import { canonicalizeServer, resolveRelative } from "../path" +import { canonicalizeServer, resolveRelative } from "../util/path" function Backlinks({ fileData, allFiles }: QuartzComponentProps) { const slug = canonicalizeServer(fileData.slug!) diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index 0651b95be..bfeb3f13b 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -1,5 +1,5 @@ -import { canonicalizeServer, pathToRoot } from "../path" -import { JSResourceToScriptElement } from "../resources" +import { canonicalizeServer, pathToRoot } from "../util/path" +import { JSResourceToScriptElement } from "../util/resources" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" export default (() => { diff --git a/quartz/components/PageList.tsx b/quartz/components/PageList.tsx index 7183acb81..83b1b070c 100644 --- a/quartz/components/PageList.tsx +++ b/quartz/components/PageList.tsx @@ -1,4 +1,4 @@ -import { CanonicalSlug, canonicalizeServer, resolveRelative } from "../path" +import { CanonicalSlug, canonicalizeServer, resolveRelative } from "../util/path" import { QuartzPluginData } from "../plugins/vfile" import { Date } from "./Date" import { QuartzComponentProps } from "./types" diff --git a/quartz/components/PageTitle.tsx b/quartz/components/PageTitle.tsx index f6319ef90..c1e74f382 100644 --- a/quartz/components/PageTitle.tsx +++ b/quartz/components/PageTitle.tsx @@ -1,4 +1,4 @@ -import { canonicalizeServer, pathToRoot } from "../path" +import { canonicalizeServer, pathToRoot } from "../util/path" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" function PageTitle({ fileData, cfg }: QuartzComponentProps) { diff --git a/quartz/components/TagList.tsx b/quartz/components/TagList.tsx index 656003503..bf5badd8d 100644 --- a/quartz/components/TagList.tsx +++ b/quartz/components/TagList.tsx @@ -1,4 +1,4 @@ -import { canonicalizeServer, pathToRoot, slugTag } from "../path" +import { canonicalizeServer, pathToRoot, slugTag } from "../util/path" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" function TagList({ fileData }: QuartzComponentProps) { diff --git a/quartz/components/pages/FolderContent.tsx b/quartz/components/pages/FolderContent.tsx index ea7ab5e5f..603793087 100644 --- a/quartz/components/pages/FolderContent.tsx +++ b/quartz/components/pages/FolderContent.tsx @@ -5,7 +5,7 @@ import path from "path" import style from "../styles/listPage.scss" import { PageList } from "../PageList" -import { canonicalizeServer } from "../../path" +import { canonicalizeServer } from "../../util/path" function FolderContent(props: QuartzComponentProps) { const { tree, fileData, allFiles } = props diff --git a/quartz/components/pages/TagContent.tsx b/quartz/components/pages/TagContent.tsx index 5d30240b7..2cae40de3 100644 --- a/quartz/components/pages/TagContent.tsx +++ b/quartz/components/pages/TagContent.tsx @@ -3,7 +3,7 @@ import { Fragment, jsx, jsxs } from "preact/jsx-runtime" import { toJsxRuntime } from "hast-util-to-jsx-runtime" import style from "../styles/listPage.scss" import { PageList } from "../PageList" -import { ServerSlug, canonicalizeServer, getAllSegmentPrefixes } from "../../path" +import { ServerSlug, canonicalizeServer, getAllSegmentPrefixes } from "../../util/path" import { QuartzPluginData } from "../../plugins/vfile" const numPages = 10 diff --git a/quartz/components/renderPage.tsx b/quartz/components/renderPage.tsx index ab93709cb..171c41467 100644 --- a/quartz/components/renderPage.tsx +++ b/quartz/components/renderPage.tsx @@ -2,8 +2,8 @@ import { render } from "preact-render-to-string" import { QuartzComponent, QuartzComponentProps } from "./types" import HeaderConstructor from "./Header" import BodyConstructor from "./Body" -import { JSResourceToScriptElement, StaticResources } from "../resources" -import { CanonicalSlug, pathToRoot } from "../path" +import { JSResourceToScriptElement, StaticResources } from "../util/resources" +import { CanonicalSlug, pathToRoot } from "../util/path" interface RenderComponents { head: QuartzComponent diff --git a/quartz/components/scripts/graph.inline.ts b/quartz/components/scripts/graph.inline.ts index f3f5cbd0c..0a7c19ee4 100644 --- a/quartz/components/scripts/graph.inline.ts +++ b/quartz/components/scripts/graph.inline.ts @@ -1,7 +1,7 @@ import type { ContentDetails } from "../../plugins/emitters/contentIndex" import * as d3 from "d3" import { registerEscapeHandler, removeAllChildren } from "./util" -import { CanonicalSlug, getCanonicalSlug, getClientSlug, resolveRelative } from "../../path" +import { CanonicalSlug, getCanonicalSlug, getClientSlug, resolveRelative } from "../../util/path" type NodeData = { id: CanonicalSlug diff --git a/quartz/components/scripts/search.inline.ts b/quartz/components/scripts/search.inline.ts index a607fe220..5c7dae012 100644 --- a/quartz/components/scripts/search.inline.ts +++ b/quartz/components/scripts/search.inline.ts @@ -1,7 +1,7 @@ import { Document } from "flexsearch" import { ContentDetails } from "../../plugins/emitters/contentIndex" import { registerEscapeHandler, removeAllChildren } from "./util" -import { CanonicalSlug, getClientSlug, resolveRelative } from "../../path" +import { CanonicalSlug, getClientSlug, resolveRelative } from "../../util/path" interface Item { id: number diff --git a/quartz/components/scripts/spa.inline.ts b/quartz/components/scripts/spa.inline.ts index 4d31b5e21..7e450b763 100644 --- a/quartz/components/scripts/spa.inline.ts +++ b/quartz/components/scripts/spa.inline.ts @@ -1,5 +1,5 @@ import micromorph from "micromorph" -import { CanonicalSlug, RelativeURL, getCanonicalSlug } from "../../path" +import { CanonicalSlug, RelativeURL, getCanonicalSlug } from "../../util/path" // adapted from `micromorph` // https://github.com/natemoo-re/micromorph diff --git a/quartz/plugins/emitters/aliases.ts b/quartz/plugins/emitters/aliases.ts index cf99d29da..1fbea7698 100644 --- a/quartz/plugins/emitters/aliases.ts +++ b/quartz/plugins/emitters/aliases.ts @@ -4,7 +4,7 @@ import { ServerSlug, canonicalizeServer, resolveRelative, -} from "../../path" +} from "../../util/path" import { QuartzEmitterPlugin } from "../types" import path from "path" diff --git a/quartz/plugins/emitters/assets.ts b/quartz/plugins/emitters/assets.ts index 0f7f3e41f..44bb71851 100644 --- a/quartz/plugins/emitters/assets.ts +++ b/quartz/plugins/emitters/assets.ts @@ -1,8 +1,8 @@ -import { FilePath, joinSegments, slugifyFilePath } from "../../path" +import { FilePath, joinSegments, slugifyFilePath } from "../../util/path" import { QuartzEmitterPlugin } from "../types" import path from "path" import fs from "fs" -import { glob } from "../../glob" +import { glob } from "../../util/glob" export const Assets: QuartzEmitterPlugin = () => { return { diff --git a/quartz/plugins/emitters/componentResources.ts b/quartz/plugins/emitters/componentResources.ts index 859109fcc..19eddc64b 100644 --- a/quartz/plugins/emitters/componentResources.ts +++ b/quartz/plugins/emitters/componentResources.ts @@ -1,4 +1,4 @@ -import { FilePath, ServerSlug } from "../../path" +import { FilePath, ServerSlug } from "../../util/path" import { QuartzEmitterPlugin } from "../types" // @ts-ignore @@ -9,10 +9,10 @@ import plausibleScript from "../../components/scripts/plausible.inline" import popoverScript from "../../components/scripts/popover.inline" import styles from "../../styles/base.scss" import popoverStyle from "../../components/styles/popover.scss" -import { BuildCtx } from "../../ctx" -import { StaticResources } from "../../resources" +import { BuildCtx } from "../../util/ctx" +import { StaticResources } from "../../util/resources" import { QuartzComponent } from "../../components/types" -import { googleFontHref, joinStyles } from "../../theme" +import { googleFontHref, joinStyles } from "../../util/theme" import { Features, transform } from "lightningcss" type ComponentResources = { diff --git a/quartz/plugins/emitters/contentIndex.ts b/quartz/plugins/emitters/contentIndex.ts index f3a0281e6..85cdfe714 100644 --- a/quartz/plugins/emitters/contentIndex.ts +++ b/quartz/plugins/emitters/contentIndex.ts @@ -1,5 +1,11 @@ import { GlobalConfiguration } from "../../cfg" -import { CanonicalSlug, ClientSlug, FilePath, ServerSlug, canonicalizeServer } from "../../path" +import { + CanonicalSlug, + ClientSlug, + FilePath, + ServerSlug, + canonicalizeServer, +} from "../../util/path" import { QuartzEmitterPlugin } from "../types" import path from "path" diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index dcf28290e..b7e347aa6 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -4,7 +4,7 @@ import HeaderConstructor from "../../components/Header" import BodyConstructor from "../../components/Body" import { pageResources, renderPage } from "../../components/renderPage" import { FullPageLayout } from "../../cfg" -import { FilePath, canonicalizeServer } from "../../path" +import { FilePath, canonicalizeServer } from "../../util/path" import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout" import { Content } from "../../components" diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx index f5bc7a6a2..724717a29 100644 --- a/quartz/plugins/emitters/folderPage.tsx +++ b/quartz/plugins/emitters/folderPage.tsx @@ -6,7 +6,13 @@ import { pageResources, renderPage } from "../../components/renderPage" import { ProcessedContent, defaultProcessedContent } from "../vfile" import { FullPageLayout } from "../../cfg" import path from "path" -import { CanonicalSlug, FilePath, ServerSlug, canonicalizeServer, joinSegments } from "../../path" +import { + CanonicalSlug, + FilePath, + ServerSlug, + canonicalizeServer, + joinSegments, +} from "../../util/path" import { defaultListPageLayout, sharedPageComponents } from "../../../quartz.layout" import { FolderContent } from "../../components" diff --git a/quartz/plugins/emitters/static.ts b/quartz/plugins/emitters/static.ts index 794cbac67..6f5d19d41 100644 --- a/quartz/plugins/emitters/static.ts +++ b/quartz/plugins/emitters/static.ts @@ -1,7 +1,7 @@ -import { FilePath, QUARTZ, joinSegments } from "../../path" +import { FilePath, QUARTZ, joinSegments } from "../../util/path" import { QuartzEmitterPlugin } from "../types" import fs from "fs" -import { glob } from "../../glob" +import { glob } from "../../util/glob" export const Static: QuartzEmitterPlugin = () => ({ name: "Static", diff --git a/quartz/plugins/emitters/tagPage.tsx b/quartz/plugins/emitters/tagPage.tsx index fd00d9c91..de0762332 100644 --- a/quartz/plugins/emitters/tagPage.tsx +++ b/quartz/plugins/emitters/tagPage.tsx @@ -11,7 +11,7 @@ import { ServerSlug, getAllSegmentPrefixes, joinSegments, -} from "../../path" +} from "../../util/path" import { defaultListPageLayout, sharedPageComponents } from "../../../quartz.layout" import { TagContent } from "../../components" @@ -41,7 +41,7 @@ export const TagPage: QuartzEmitterPlugin = (userOpts) => { allFiles.flatMap((data) => data.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes), ) // add base tag - tags.add("") + tags.add("index") const tagDescriptions: Record = Object.fromEntries( [...tags].map((tag) => { diff --git a/quartz/plugins/index.ts b/quartz/plugins/index.ts index 23440fbe1..c83455e47 100644 --- a/quartz/plugins/index.ts +++ b/quartz/plugins/index.ts @@ -1,6 +1,6 @@ -import { StaticResources } from "../resources" -import { FilePath, ServerSlug } from "../path" -import { BuildCtx } from "../ctx" +import { StaticResources } from "../util/resources" +import { FilePath, ServerSlug } from "../util/path" +import { BuildCtx } from "../util/ctx" export function getStaticResourcesFromPlugins(ctx: BuildCtx) { const staticResources: StaticResources = { diff --git a/quartz/plugins/transformers/frontmatter.ts b/quartz/plugins/transformers/frontmatter.ts index e09d20f76..5b067f63f 100644 --- a/quartz/plugins/transformers/frontmatter.ts +++ b/quartz/plugins/transformers/frontmatter.ts @@ -2,7 +2,7 @@ import matter from "gray-matter" import remarkFrontmatter from "remark-frontmatter" import { QuartzTransformerPlugin } from "../types" import yaml from "js-yaml" -import { slugTag } from "../../path" +import { slugTag } from "../../util/path" export interface Options { delims: string | string[] diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index 10b527c9c..a2607196e 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -8,7 +8,7 @@ import { joinSegments, splitAnchor, transformLink, -} from "../../path" +} from "../../util/path" import path from "path" import { visit } from "unist-util-visit" import isAbsoluteUrl from "is-absolute-url" diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index ba3fb9e5b..97054b1fb 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -6,10 +6,10 @@ import { slug as slugAnchor } from "github-slugger" import rehypeRaw from "rehype-raw" import { visit } from "unist-util-visit" import path from "path" -import { JSResource } from "../../resources" +import { JSResource } from "../../util/resources" // @ts-ignore import calloutScript from "../../components/scripts/callout.inline.ts" -import { FilePath, canonicalizeServer, pathToRoot, slugTag, slugifyFilePath } from "../../path" +import { FilePath, canonicalizeServer, pathToRoot, slugTag, slugifyFilePath } from "../../util/path" import { toHast } from "mdast-util-to-hast" import { toHtml } from "hast-util-to-html" import { PhrasingContent } from "mdast-util-find-and-replace/lib" @@ -294,7 +294,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin } const text = firstChild.children[0].value - const restChildren = firstChild.children.splice(1) + const restChildren = firstChild.children.slice(1) const [firstLine, ...remainingLines] = text.split("\n") const remainingText = remainingLines.join("\n") diff --git a/quartz/plugins/types.ts b/quartz/plugins/types.ts index 2662aeda5..ad1881b83 100644 --- a/quartz/plugins/types.ts +++ b/quartz/plugins/types.ts @@ -1,9 +1,9 @@ import { PluggableList } from "unified" -import { StaticResources } from "../resources" +import { StaticResources } from "../util/resources" import { ProcessedContent } from "./vfile" import { QuartzComponent } from "../components/types" -import { FilePath, ServerSlug } from "../path" -import { BuildCtx } from "../ctx" +import { FilePath, ServerSlug } from "../util/path" +import { BuildCtx } from "../util/ctx" export interface PluginTypes { transformers: QuartzTransformerPluginInstance[] diff --git a/quartz/processors/emit.ts b/quartz/processors/emit.ts index fd3268568..3b357aa94 100644 --- a/quartz/processors/emit.ts +++ b/quartz/processors/emit.ts @@ -1,13 +1,13 @@ import path from "path" import fs from "fs" -import { PerfTimer } from "../perf" +import { PerfTimer } from "../util/perf" import { getStaticResourcesFromPlugins } from "../plugins" import { EmitCallback } from "../plugins/types" import { ProcessedContent } from "../plugins/vfile" -import { FilePath, joinSegments } from "../path" -import { QuartzLogger } from "../log" -import { trace } from "../trace" -import { BuildCtx } from "../ctx" +import { FilePath, joinSegments } from "../util/path" +import { QuartzLogger } from "../util/log" +import { trace } from "../util/trace" +import { BuildCtx } from "../util/ctx" export async function emitContent(ctx: BuildCtx, content: ProcessedContent[]) { const { argv, cfg } = ctx diff --git a/quartz/processors/filter.ts b/quartz/processors/filter.ts index dae6a3d21..b269fb313 100644 --- a/quartz/processors/filter.ts +++ b/quartz/processors/filter.ts @@ -1,5 +1,5 @@ -import { BuildCtx } from "../ctx" -import { PerfTimer } from "../perf" +import { BuildCtx } from "../util/ctx" +import { PerfTimer } from "../util/perf" import { ProcessedContent } from "../plugins/vfile" export function filterContent(ctx: BuildCtx, content: ProcessedContent[]): ProcessedContent[] { diff --git a/quartz/processors/parse.ts b/quartz/processors/parse.ts index 00155279a..29f92fc45 100644 --- a/quartz/processors/parse.ts +++ b/quartz/processors/parse.ts @@ -5,14 +5,14 @@ import { Processor, unified } from "unified" import { Root as MDRoot } from "remark-parse/lib" import { Root as HTMLRoot } from "hast" import { ProcessedContent } from "../plugins/vfile" -import { PerfTimer } from "../perf" +import { PerfTimer } from "../util/perf" import { read } from "to-vfile" -import { FilePath, QUARTZ, slugifyFilePath } from "../path" +import { FilePath, QUARTZ, slugifyFilePath } from "../util/path" import path from "path" import workerpool, { Promise as WorkerPromise } from "workerpool" -import { QuartzLogger } from "../log" -import { trace } from "../trace" -import { BuildCtx } from "../ctx" +import { QuartzLogger } from "../util/log" +import { trace } from "../util/trace" +import { BuildCtx } from "../util/ctx" export type QuartzProcessor = Processor export function createProcessor(ctx: BuildCtx): QuartzProcessor { diff --git a/quartz/ctx.ts b/quartz/util/ctx.ts similarity index 87% rename from quartz/ctx.ts rename to quartz/util/ctx.ts index dad5cef5e..b1278398b 100644 --- a/quartz/ctx.ts +++ b/quartz/util/ctx.ts @@ -1,4 +1,4 @@ -import { QuartzConfig } from "./cfg" +import { QuartzConfig } from "../cfg" import { ServerSlug } from "./path" export interface Argv { diff --git a/quartz/glob.ts b/quartz/util/glob.ts similarity index 100% rename from quartz/glob.ts rename to quartz/util/glob.ts diff --git a/quartz/log.ts b/quartz/util/log.ts similarity index 100% rename from quartz/log.ts rename to quartz/util/log.ts diff --git a/quartz/path.test.ts b/quartz/util/path.test.ts similarity index 96% rename from quartz/path.test.ts rename to quartz/util/path.test.ts index d86bca5f8..5655585df 100644 --- a/quartz/path.test.ts +++ b/quartz/util/path.test.ts @@ -53,8 +53,6 @@ describe("typeguards", () => { assert(!path.isRelativeURL("abc")) assert(!path.isRelativeURL("/abc/def")) assert(!path.isRelativeURL("")) - assert(!path.isRelativeURL("../")) - assert(!path.isRelativeURL("./")) assert(!path.isRelativeURL("./abc/def.html")) assert(!path.isRelativeURL("./abc/def.md")) }) @@ -160,17 +158,18 @@ describe("transforms", () => { [ ["", "."], [".", "."], - ["./", "."], - ["./index", "."], - ["./index.html", "."], - ["./index.md", "."], + ["./", "./"], + ["./index", "./"], + ["./index.html", "./"], + ["./index.md", "./"], ["content", "./content"], ["content/test.md", "./content/test"], ["./content/test.md", "./content/test"], ["../content/test.md", "../content/test"], - ["tags/", "./tags"], - ["/tags/", "./tags"], + ["tags/", "./tags/"], + ["/tags/", "./tags/"], ["content/with spaces", "./content/with-spaces"], + ["content/with spaces/index", "./content/with-spaces/"], ["content/with spaces#and Anchor!", "./content/with-spaces#and-anchor"], ], path.transformInternalLink, @@ -269,16 +268,16 @@ describe("link strategies", () => { test("from a/b/c", () => { const cur = "a/b/c" as CanonicalSlug assert.strictEqual(path.transformLink(cur, "d", opts), "./d") - assert.strictEqual(path.transformLink(cur, "index", opts), ".") - assert.strictEqual(path.transformLink(cur, "../../index", opts), "../..") - assert.strictEqual(path.transformLink(cur, "../../", opts), "../..") + assert.strictEqual(path.transformLink(cur, "index", opts), "./") + assert.strictEqual(path.transformLink(cur, "../../index", opts), "../../") + assert.strictEqual(path.transformLink(cur, "../../", opts), "../../") assert.strictEqual(path.transformLink(cur, "../../e/g/h", opts), "../../e/g/h") }) test("from a/b/index", () => { const cur = "a/b" as CanonicalSlug - assert.strictEqual(path.transformLink(cur, "../../index", opts), "../..") - assert.strictEqual(path.transformLink(cur, "../../", opts), "../..") + assert.strictEqual(path.transformLink(cur, "../../index", opts), "../../") + assert.strictEqual(path.transformLink(cur, "../../", opts), "../../") assert.strictEqual(path.transformLink(cur, "../../e/g/h", opts), "../../e/g/h") assert.strictEqual(path.transformLink(cur, "c", opts), "./c") }) @@ -286,7 +285,7 @@ describe("link strategies", () => { test("from index", () => { const cur = "" as CanonicalSlug assert.strictEqual(path.transformLink(cur, "e/g/h", opts), "./e/g/h") - assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "./a/b") + assert.strictEqual(path.transformLink(cur, "a/b/index", opts), "./a/b/") }) }) }) diff --git a/quartz/path.ts b/quartz/util/path.ts similarity index 96% rename from quartz/path.ts rename to quartz/util/path.ts index 8588c21f0..c1016af55 100644 --- a/quartz/path.ts +++ b/quartz/util/path.ts @@ -71,7 +71,7 @@ export function isCanonicalSlug(s: string): s is CanonicalSlug { export type RelativeURL = SlugLike<"relative"> export function isRelativeURL(s: string): s is RelativeURL { const validStart = /^\.{1,2}/.test(s) - const validEnding = !(s.endsWith("/") || s.endsWith("/index") || s === "index") + const validEnding = !(s.endsWith("/index") || s === "index") return validStart && validEnding && !_hasFileExtension(s) } @@ -133,6 +133,12 @@ export function slugifyFilePath(fp: FilePath): ServerSlug { export function transformInternalLink(link: string): RelativeURL { let [fplike, anchor] = splitAnchor(decodeURI(link)) + + const folderPath = + fplike.endsWith("index") || + fplike.endsWith("index.md") || + fplike.endsWith("index.html") || + fplike.endsWith("/") let segments = fplike.split("/").filter((x) => x.length > 0) let prefix = segments.filter(_isRelativeSegment).join("/") let fp = segments.filter((seg) => !_isRelativeSegment(seg)).join("/") @@ -143,14 +149,13 @@ export function transformInternalLink(link: string): RelativeURL { } fp = canonicalizeServer(slugifyFilePath(fp as FilePath)) - fp = _trimSuffix(fp, "index") - - let joined = joinSegments(_stripSlashes(prefix), _stripSlashes(fp)) - const res = (_addRelativeToStart(joined) + anchor) as RelativeURL + const joined = joinSegments(_stripSlashes(prefix), _stripSlashes(fp)) + const trail = folderPath ? "/" : "" + const res = (_addRelativeToStart(joined) + anchor + trail) as RelativeURL return res } -// resolve /a/b/c to ../../ +// resolve /a/b/c to ../../.. export function pathToRoot(slug: CanonicalSlug): RelativeURL { let rootPath = slug .split("/") diff --git a/quartz/perf.ts b/quartz/util/perf.ts similarity index 100% rename from quartz/perf.ts rename to quartz/util/perf.ts diff --git a/quartz/resources.tsx b/quartz/util/resources.tsx similarity index 100% rename from quartz/resources.tsx rename to quartz/util/resources.tsx diff --git a/quartz/sourcemap.ts b/quartz/util/sourcemap.ts similarity index 100% rename from quartz/sourcemap.ts rename to quartz/util/sourcemap.ts diff --git a/quartz/theme.ts b/quartz/util/theme.ts similarity index 100% rename from quartz/theme.ts rename to quartz/util/theme.ts diff --git a/quartz/trace.ts b/quartz/util/trace.ts similarity index 100% rename from quartz/trace.ts rename to quartz/util/trace.ts diff --git a/quartz/worker.ts b/quartz/worker.ts index db11cbbcc..d42bc2516 100644 --- a/quartz/worker.ts +++ b/quartz/worker.ts @@ -1,7 +1,7 @@ import sourceMapSupport from "source-map-support" sourceMapSupport.install(options) import cfg from "../quartz.config" -import { Argv, BuildCtx } from "./ctx" +import { Argv, BuildCtx } from "./util/ctx" import { FilePath, ServerSlug } from "./path" import { createFileParser, createProcessor } from "./processors/parse" import { options } from "./sourcemap"