From d7842e0ce713e338f21374cea407a46cace18cca Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Wed, 2 Aug 2023 22:10:13 -0700 Subject: [PATCH] make path and globbing more platform invariant --- quartz.config.ts | 2 +- quartz/build.ts | 13 +++----- quartz/glob.ts | 18 +++++++++++ quartz/plugins/emitters/assets.ts | 48 ++++++++-------------------- quartz/plugins/emitters/static.ts | 12 +++---- quartz/plugins/transformers/links.ts | 2 +- quartz/processors/emit.ts | 4 +-- 7 files changed, 45 insertions(+), 54 deletions(-) create mode 100644 quartz/glob.ts diff --git a/quartz.config.ts b/quartz.config.ts index bd7abfb69..447039d62 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -66,7 +66,7 @@ const config: QuartzConfig = { enableSiteMap: true, enableRSS: true, }), - Plugin.Assets({ attachmentsFolder: "attachments" }), + Plugin.Assets(), Plugin.Static(), ], }, diff --git a/quartz/build.ts b/quartz/build.ts index 9bd1e670e..688f735d2 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -2,7 +2,7 @@ import "source-map-support/register.js" import path from "path" import { PerfTimer } from "./perf" import { rimraf } from "rimraf" -import { globby, isGitIgnored } from "globby" +import { isGitIgnored } from "globby" import chalk from "chalk" import http from "http" import serveHandler from "serve-handler" @@ -15,6 +15,7 @@ import chokidar from "chokidar" import { ProcessedContent } from "./plugins/vfile" import WebSocket, { WebSocketServer } from "ws" import { Argv, BuildCtx } from "./ctx" +import { glob, toPosixPath } from "./glob" async function buildQuartz(argv: Argv, version: string) { const ctx: BuildCtx = { @@ -42,13 +43,7 @@ async function buildQuartz(argv: Argv, version: string) { console.log(`Cleaned output directory \`${output}\` in ${perf.timeSince("clean")}`) perf.addEvent("glob") - const fps = ( - await globby("**/*.md", { - cwd: argv.directory, - ignore: cfg.configuration.ignorePatterns, - gitignore: true, - }) - ).map((fp) => fp.split(path.sep).join(path.posix.sep)) + const fps = await glob("**/*.md", argv.directory, cfg.configuration.ignorePatterns) console.log( `Found ${fps.length} input files from \`${argv.directory}\` in ${perf.timeSince("glob")}`, ) @@ -83,7 +78,7 @@ async function startServing(ctx: BuildCtx, initialContent: ProcessedContent[]) { let toRebuild: Set = new Set() let toRemove: Set = new Set() async function rebuild(fp: string, action: "add" | "change" | "delete") { - fp = fp.split(path.sep).join(path.posix.sep) + fp = toPosixPath(fp) if (!ignored(fp)) { const filePath = joinSegments(argv.directory, fp) as FilePath if (action === "add" || action === "change") { diff --git a/quartz/glob.ts b/quartz/glob.ts new file mode 100644 index 000000000..dcfa61b32 --- /dev/null +++ b/quartz/glob.ts @@ -0,0 +1,18 @@ +import path from "path"; +import { FilePath } from "./path"; +import { globby } from "globby"; + +export function toPosixPath(fp: string): string { + return fp.split(path.sep).join("/") +} + +export async function glob(pattern: string, cwd: string, ignorePatterns: string[]): Promise { + const fps = ( + await globby(pattern, { + cwd, + ignore: ignorePatterns, + gitignore: true, + }) + ).map(toPosixPath) + return fps as FilePath[] +} diff --git a/quartz/plugins/emitters/assets.ts b/quartz/plugins/emitters/assets.ts index d231d1d23..8ea3055d9 100644 --- a/quartz/plugins/emitters/assets.ts +++ b/quartz/plugins/emitters/assets.ts @@ -1,55 +1,33 @@ -import { globbyStream } from "globby" -import { FilePath, slugifyFilePath } from "../../path" +import { FilePath, joinSegments, slugifyFilePath } from "../../path" import { QuartzEmitterPlugin } from "../types" import path from "path" import fs from "fs" +import { glob } from "../../glob" -interface Options { - attachmentsFolder: string | null -} - -const defaultOptions: Options = { - attachmentsFolder: null, -} - -export const Assets: QuartzEmitterPlugin = (userOpts?: Options) => { - const { attachmentsFolder } = { ...defaultOptions, ...userOpts } - +export const Assets: QuartzEmitterPlugin = () => { return { name: "Assets", getQuartzComponents() { return [] }, - async emit({ argv }, _content, _resources, _emit): Promise { + async emit({ argv, cfg }, _content, _resources, _emit): Promise { // glob all non MD/MDX/HTML files in content folder and copy it over - const assetsPath = path.join(argv.output, "assets") - - const fps: FilePath[] = [] - for await (const rawFp of globbyStream("**", { - ignore: ["**/*.md"], - cwd: argv.directory, - })) { - const fp = rawFp as FilePath + const assetsPath = joinSegments(argv.output, "assets") + const fps = await glob("**", argv.directory, ["**/*.md", ...cfg.configuration.ignorePatterns]) + const res: FilePath[] = [] + for (const fp of fps) { const ext = path.extname(fp) - const src = path.join(argv.directory, fp) as FilePath - let name = (slugifyFilePath(fp as FilePath) + ext) as FilePath + const src = joinSegments(argv.directory, fp) as FilePath + const name = (slugifyFilePath(fp as FilePath) + ext) as FilePath - if (attachmentsFolder) { - const segments = name.split("/") - if (segments.at(-2) === attachmentsFolder) { - segments.splice(-2, 1) - name = segments.join("/") as FilePath - } - } - - const dest = path.join(assetsPath, name) as FilePath + const dest = joinSegments(assetsPath, name) as FilePath const dir = path.dirname(dest) as FilePath await fs.promises.mkdir(dir, { recursive: true }) // ensure dir exists await fs.promises.copyFile(src, dest) - fps.push(path.join("assets", fp) as FilePath) + res.push(joinSegments("assets", fp) as FilePath) } - return fps + return res }, } } diff --git a/quartz/plugins/emitters/static.ts b/quartz/plugins/emitters/static.ts index fa30327f6..043a4619c 100644 --- a/quartz/plugins/emitters/static.ts +++ b/quartz/plugins/emitters/static.ts @@ -1,18 +1,18 @@ -import { globby } from "globby" -import { FilePath, QUARTZ } from "../../path" +import { FilePath, QUARTZ, joinSegments } from "../../path" import { QuartzEmitterPlugin } from "../types" import path from "path" import fs from "fs" +import { glob } from "../../glob" export const Static: QuartzEmitterPlugin = () => ({ name: "Static", getQuartzComponents() { return [] }, - async emit({ argv }, _content, _resources, _emit): Promise { + async emit({ argv, cfg }, _content, _resources, _emit): Promise { const staticPath = path.join(QUARTZ, "static") - const fps = await globby("*", { cwd: staticPath }) - await fs.promises.cp(staticPath, path.join(argv.output, "static"), { recursive: true }) - return fps.map((fp) => path.join("static", fp)) as FilePath[] + const fps = await glob("**", staticPath, cfg.configuration.ignorePatterns) + await fs.promises.cp(staticPath, joinSegments(argv.output, "static"), { recursive: true }) + return fps.map((fp) => joinSegments("static", fp)) as FilePath[] }, }) diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index f5bfdfc62..aecb58f80 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -100,7 +100,7 @@ export const CrawlLinks: QuartzTransformerPlugin | undefined> = if (!isAbsoluteUrl(node.properties.src)) { const ext = path.extname(node.properties.src) node.properties.src = - transformLink(path.join("assets", node.properties.src)) + ext + transformLink(joinSegments("assets", node.properties.src)) + ext } } }) diff --git a/quartz/processors/emit.ts b/quartz/processors/emit.ts index 72d6085a0..960f1e43a 100644 --- a/quartz/processors/emit.ts +++ b/quartz/processors/emit.ts @@ -4,7 +4,7 @@ import { PerfTimer } from "../perf" import { getStaticResourcesFromPlugins } from "../plugins" import { EmitCallback } from "../plugins/types" import { ProcessedContent } from "../plugins/vfile" -import { FilePath } from "../path" +import { FilePath, joinSegments } from "../path" import { QuartzLogger } from "../log" import { trace } from "../trace" import { BuildCtx } from "../ctx" @@ -16,7 +16,7 @@ export async function emitContent(ctx: BuildCtx, content: ProcessedContent[]) { log.start(`Emitting output files`) const emit: EmitCallback = async ({ slug, ext, content }) => { - const pathToPage = path.join(argv.output, slug + ext) as FilePath + const pathToPage = joinSegments(argv.output, slug + ext) as FilePath const dir = path.dirname(pathToPage) await fs.promises.mkdir(dir, { recursive: true }) await fs.promises.writeFile(pathToPage, content)