more robust error handling, config hotreload
This commit is contained in:
parent
6a7ee31c7c
commit
27baf57dd1
@ -4,8 +4,6 @@ draft: true
|
|||||||
|
|
||||||
## high priority
|
## high priority
|
||||||
|
|
||||||
- images in same folder are broken on shortest path mode
|
|
||||||
- watch mode for config/source code
|
|
||||||
- block links: https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note
|
- block links: https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note
|
||||||
- note/header/block transcludes: https://help.obsidian.md/Linking+notes+and+files/Embedding+files
|
- note/header/block transcludes: https://help.obsidian.md/Linking+notes+and+files/Embedding+files
|
||||||
|
|
||||||
@ -22,7 +20,5 @@ draft: true
|
|||||||
- https://help.obsidian.md/Advanced+topics/Using+Obsidian+URI
|
- https://help.obsidian.md/Advanced+topics/Using+Obsidian+URI
|
||||||
- audio/video embed styling
|
- audio/video embed styling
|
||||||
- Canvas
|
- Canvas
|
||||||
- mermaid styling: https://mermaid.js.org/config/theming.html#theme-variables-reference-table
|
|
||||||
- https://github.com/jackyzha0/quartz/issues/331
|
|
||||||
- parse all images in page: use this for page lists if applicable?
|
- parse all images in page: use this for page lists if applicable?
|
||||||
- CV mode? with print stylesheet
|
- CV mode? with print stylesheet
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@jackyzha0/quartz",
|
"name": "@jackyzha0/quartz",
|
||||||
"version": "4.0.6",
|
"version": "4.0.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@jackyzha0/quartz",
|
"name": "@jackyzha0/quartz",
|
||||||
"version": "4.0.6",
|
"version": "4.0.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/prompts": "^0.6.3",
|
"@clack/prompts": "^0.6.3",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "@jackyzha0/quartz",
|
"name": "@jackyzha0/quartz",
|
||||||
"description": "🌱 publish your digital garden and notes as a website",
|
"description": "🌱 publish your digital garden and notes as a website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "4.0.6",
|
"version": "4.0.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "jackyzha0 <j.zhao2k19@gmail.com>",
|
"author": "jackyzha0 <j.zhao2k19@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -9,9 +9,13 @@ import { sassPlugin } from "esbuild-sass-plugin"
|
|||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import { intro, isCancel, outro, select, text } from "@clack/prompts"
|
import { intro, isCancel, outro, select, text } from "@clack/prompts"
|
||||||
import { rimraf } from "rimraf"
|
import { rimraf } from "rimraf"
|
||||||
|
import chokidar from "chokidar"
|
||||||
import prettyBytes from "pretty-bytes"
|
import prettyBytes from "pretty-bytes"
|
||||||
import { execSync, spawnSync } from "child_process"
|
import { execSync, spawnSync } from "child_process"
|
||||||
import { transform as cssTransform } from "lightningcss"
|
import { transform as cssTransform } from "lightningcss"
|
||||||
|
import http from "http"
|
||||||
|
import serveHandler from "serve-handler"
|
||||||
|
import { WebSocketServer } from "ws"
|
||||||
|
|
||||||
const ORIGIN_NAME = "origin"
|
const ORIGIN_NAME = "origin"
|
||||||
const UPSTREAM_NAME = "upstream"
|
const UPSTREAM_NAME = "upstream"
|
||||||
@ -287,86 +291,132 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started.
|
|||||||
console.log(chalk.green("Done!"))
|
console.log(chalk.green("Done!"))
|
||||||
})
|
})
|
||||||
.command("build", "Build Quartz into a bundle of static HTML files", BuildArgv, async (argv) => {
|
.command("build", "Build Quartz into a bundle of static HTML files", BuildArgv, async (argv) => {
|
||||||
const result = await esbuild
|
console.log(chalk.bgGreen.black(`\n Quartz v${version} \n`))
|
||||||
.build({
|
const ctx = await esbuild.context({
|
||||||
entryPoints: [fp],
|
entryPoints: [fp],
|
||||||
outfile: path.join("quartz", cacheFile),
|
outfile: path.join("quartz", cacheFile),
|
||||||
bundle: true,
|
bundle: true,
|
||||||
keepNames: true,
|
keepNames: true,
|
||||||
minify: true,
|
minify: true,
|
||||||
platform: "node",
|
platform: "node",
|
||||||
format: "esm",
|
format: "esm",
|
||||||
jsx: "automatic",
|
jsx: "automatic",
|
||||||
jsxImportSource: "preact",
|
jsxImportSource: "preact",
|
||||||
packages: "external",
|
packages: "external",
|
||||||
metafile: true,
|
metafile: true,
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
plugins: [
|
plugins: [
|
||||||
sassPlugin({
|
sassPlugin({
|
||||||
type: "css-text",
|
type: "css-text",
|
||||||
cssImports: true,
|
cssImports: true,
|
||||||
async transform(css) {
|
async transform(css) {
|
||||||
const { code } = cssTransform({
|
const { code } = cssTransform({
|
||||||
filename: "style.css",
|
filename: "style.css",
|
||||||
code: Buffer.from(css),
|
code: Buffer.from(css),
|
||||||
minify: true,
|
minify: true,
|
||||||
})
|
})
|
||||||
return code.toString()
|
return code.toString()
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "inline-script-loader",
|
|
||||||
setup(build) {
|
|
||||||
build.onLoad({ filter: /\.inline\.(ts|js)$/ }, async (args) => {
|
|
||||||
let text = await promises.readFile(args.path, "utf8")
|
|
||||||
|
|
||||||
// remove default exports that we manually inserted
|
|
||||||
text = text.replace("export default", "")
|
|
||||||
text = text.replace("export", "")
|
|
||||||
|
|
||||||
const sourcefile = path.relative(path.resolve("."), args.path)
|
|
||||||
const resolveDir = path.dirname(sourcefile)
|
|
||||||
const transpiled = await esbuild.build({
|
|
||||||
stdin: {
|
|
||||||
contents: text,
|
|
||||||
loader: "ts",
|
|
||||||
resolveDir,
|
|
||||||
sourcefile,
|
|
||||||
},
|
|
||||||
write: false,
|
|
||||||
bundle: true,
|
|
||||||
platform: "browser",
|
|
||||||
format: "esm",
|
|
||||||
})
|
|
||||||
const rawMod = transpiled.outputFiles[0].text
|
|
||||||
return {
|
|
||||||
contents: rawMod,
|
|
||||||
loader: "text",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
}),
|
||||||
})
|
{
|
||||||
.catch((err) => {
|
name: "inline-script-loader",
|
||||||
|
setup(build) {
|
||||||
|
build.onLoad({ filter: /\.inline\.(ts|js)$/ }, async (args) => {
|
||||||
|
let text = await promises.readFile(args.path, "utf8")
|
||||||
|
|
||||||
|
// remove default exports that we manually inserted
|
||||||
|
text = text.replace("export default", "")
|
||||||
|
text = text.replace("export", "")
|
||||||
|
|
||||||
|
const sourcefile = path.relative(path.resolve("."), args.path)
|
||||||
|
const resolveDir = path.dirname(sourcefile)
|
||||||
|
const transpiled = await esbuild.build({
|
||||||
|
stdin: {
|
||||||
|
contents: text,
|
||||||
|
loader: "ts",
|
||||||
|
resolveDir,
|
||||||
|
sourcefile,
|
||||||
|
},
|
||||||
|
write: false,
|
||||||
|
bundle: true,
|
||||||
|
platform: "browser",
|
||||||
|
format: "esm",
|
||||||
|
})
|
||||||
|
const rawMod = transpiled.outputFiles[0].text
|
||||||
|
return {
|
||||||
|
contents: rawMod,
|
||||||
|
loader: "text",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
let clientRefresh = () => {}
|
||||||
|
let closeHandler = null
|
||||||
|
const build = async () => {
|
||||||
|
const result = await ctx.rebuild().catch((err) => {
|
||||||
console.error(`${chalk.red("Couldn't parse Quartz configuration:")} ${fp}`)
|
console.error(`${chalk.red("Couldn't parse Quartz configuration:")} ${fp}`)
|
||||||
console.log(`Reason: ${chalk.grey(err)}`)
|
console.log(`Reason: ${chalk.grey(err)}`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (argv.bundleInfo) {
|
if (argv.bundleInfo) {
|
||||||
const outputFileName = "quartz/.quartz-cache/transpiled-build.mjs"
|
const outputFileName = "quartz/.quartz-cache/transpiled-build.mjs"
|
||||||
const meta = result.metafile.outputs[outputFileName]
|
const meta = result.metafile.outputs[outputFileName]
|
||||||
console.log(
|
console.log(
|
||||||
`Successfully transpiled ${Object.keys(meta.inputs).length} files (${prettyBytes(
|
`Successfully transpiled ${Object.keys(meta.inputs).length} files (${prettyBytes(
|
||||||
meta.bytes,
|
meta.bytes,
|
||||||
)})`,
|
)})`,
|
||||||
)
|
)
|
||||||
console.log(await esbuild.analyzeMetafile(result.metafile, { color: true }))
|
console.log(await esbuild.analyzeMetafile(result.metafile, { color: true }))
|
||||||
|
}
|
||||||
|
|
||||||
|
// bypass module cache
|
||||||
|
const { default: buildQuartz } = await import(cacheFile + `?update=${new Date()}`)
|
||||||
|
if (closeHandler) {
|
||||||
|
await closeHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
closeHandler = await buildQuartz(argv, clientRefresh)
|
||||||
|
clientRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
const { default: buildQuartz } = await import(cacheFile)
|
await build()
|
||||||
buildQuartz(argv, version)
|
if (argv.serve) {
|
||||||
|
const wss = new WebSocketServer({ port: 3001 })
|
||||||
|
const connections = []
|
||||||
|
wss.on("connection", (ws) => connections.push(ws))
|
||||||
|
clientRefresh = () => connections.forEach((conn) => conn.send("rebuild"))
|
||||||
|
const server = http.createServer(async (req, res) => {
|
||||||
|
await serveHandler(req, res, {
|
||||||
|
public: argv.output,
|
||||||
|
directoryListing: false,
|
||||||
|
})
|
||||||
|
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}`))
|
||||||
|
})
|
||||||
|
server.listen(argv.port)
|
||||||
|
console.log(chalk.cyan(`Started a Quartz server listening at http://localhost:${argv.port}`))
|
||||||
|
console.log("hint: exit with ctrl+c")
|
||||||
|
chokidar
|
||||||
|
.watch(["**/*.ts", "**/*.tsx", "**/*.scss", "package.json"], {
|
||||||
|
ignoreInitial: true,
|
||||||
|
})
|
||||||
|
.on("all", async () => {
|
||||||
|
console.log(chalk.yellow("Detected a source code change, doing a hard rebuild..."))
|
||||||
|
await build()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.dispose()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.showHelpOnFail(false)
|
.showHelpOnFail(false)
|
||||||
.help()
|
.help()
|
||||||
|
@ -4,8 +4,6 @@ import { PerfTimer } from "./perf"
|
|||||||
import { rimraf } from "rimraf"
|
import { rimraf } from "rimraf"
|
||||||
import { isGitIgnored } from "globby"
|
import { isGitIgnored } from "globby"
|
||||||
import chalk from "chalk"
|
import chalk from "chalk"
|
||||||
import http from "http"
|
|
||||||
import serveHandler from "serve-handler"
|
|
||||||
import { parseMarkdown } from "./processors/parse"
|
import { parseMarkdown } from "./processors/parse"
|
||||||
import { filterContent } from "./processors/filter"
|
import { filterContent } from "./processors/filter"
|
||||||
import { emitContent } from "./processors/emit"
|
import { emitContent } from "./processors/emit"
|
||||||
@ -13,18 +11,17 @@ import cfg from "../quartz.config"
|
|||||||
import { FilePath, joinSegments, slugifyFilePath } from "./path"
|
import { FilePath, joinSegments, slugifyFilePath } from "./path"
|
||||||
import chokidar from "chokidar"
|
import chokidar from "chokidar"
|
||||||
import { ProcessedContent } from "./plugins/vfile"
|
import { ProcessedContent } from "./plugins/vfile"
|
||||||
import WebSocket, { WebSocketServer } from "ws"
|
|
||||||
import { Argv, BuildCtx } from "./ctx"
|
import { Argv, BuildCtx } from "./ctx"
|
||||||
import { glob, toPosixPath } from "./glob"
|
import { glob, toPosixPath } from "./glob"
|
||||||
|
import { trace } from "./trace"
|
||||||
|
|
||||||
async function buildQuartz(argv: Argv, version: string) {
|
async function buildQuartz(argv: Argv, clientRefresh: () => void) {
|
||||||
const ctx: BuildCtx = {
|
const ctx: BuildCtx = {
|
||||||
argv,
|
argv,
|
||||||
cfg,
|
cfg,
|
||||||
allSlugs: [],
|
allSlugs: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(chalk.bgGreen.black(`\n Quartz v${version} \n`))
|
|
||||||
const perf = new PerfTimer()
|
const perf = new PerfTimer()
|
||||||
const output = argv.output
|
const output = argv.output
|
||||||
|
|
||||||
@ -57,15 +54,17 @@ async function buildQuartz(argv: Argv, version: string) {
|
|||||||
console.log(chalk.green(`Done processing ${fps.length} files in ${perf.timeSince()}`))
|
console.log(chalk.green(`Done processing ${fps.length} files in ${perf.timeSince()}`))
|
||||||
|
|
||||||
if (argv.serve) {
|
if (argv.serve) {
|
||||||
await startServing(ctx, parsedFiles)
|
return startServing(ctx, parsedFiles, clientRefresh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startServing(ctx: BuildCtx, initialContent: ProcessedContent[]) {
|
// setup watcher for rebuilds
|
||||||
|
async function startServing(
|
||||||
|
ctx: BuildCtx,
|
||||||
|
initialContent: ProcessedContent[],
|
||||||
|
clientRefresh: () => void,
|
||||||
|
) {
|
||||||
const { argv } = ctx
|
const { argv } = ctx
|
||||||
const wss = new WebSocketServer({ port: 3001 })
|
|
||||||
const connections: WebSocket[] = []
|
|
||||||
wss.on("connection", (ws) => connections.push(ws))
|
|
||||||
|
|
||||||
const ignored = await isGitIgnored()
|
const ignored = await isGitIgnored()
|
||||||
const contentMap = new Map<FilePath, ProcessedContent>()
|
const contentMap = new Map<FilePath, ProcessedContent>()
|
||||||
@ -78,6 +77,12 @@ async function startServing(ctx: BuildCtx, initialContent: ProcessedContent[]) {
|
|||||||
let toRebuild: Set<FilePath> = new Set()
|
let toRebuild: Set<FilePath> = new Set()
|
||||||
let toRemove: Set<FilePath> = new Set()
|
let toRemove: Set<FilePath> = new Set()
|
||||||
async function rebuild(fp: string, action: "add" | "change" | "delete") {
|
async function rebuild(fp: string, action: "add" | "change" | "delete") {
|
||||||
|
if (path.extname(fp) !== ".md") {
|
||||||
|
// dont bother rebuilding for non-content files, just refresh
|
||||||
|
clientRefresh()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fp = toPosixPath(fp)
|
fp = toPosixPath(fp)
|
||||||
if (!ignored(fp)) {
|
if (!ignored(fp)) {
|
||||||
const filePath = joinSegments(argv.directory, fp) as FilePath
|
const filePath = joinSegments(argv.directory, fp) as FilePath
|
||||||
@ -120,7 +125,8 @@ async function startServing(ctx: BuildCtx, initialContent: ProcessedContent[]) {
|
|||||||
} catch {
|
} catch {
|
||||||
console.log(chalk.yellow(`Rebuild failed. Waiting on a change to fix the error...`))
|
console.log(chalk.yellow(`Rebuild failed. Waiting on a change to fix the error...`))
|
||||||
}
|
}
|
||||||
connections.forEach((conn) => conn.send("rebuild"))
|
|
||||||
|
clientRefresh()
|
||||||
toRebuild.clear()
|
toRebuild.clear()
|
||||||
toRemove.clear()
|
toRemove.clear()
|
||||||
}, 250)
|
}, 250)
|
||||||
@ -137,31 +143,12 @@ async function startServing(ctx: BuildCtx, initialContent: ProcessedContent[]) {
|
|||||||
.on("add", (fp) => rebuild(fp, "add"))
|
.on("add", (fp) => rebuild(fp, "add"))
|
||||||
.on("change", (fp) => rebuild(fp, "change"))
|
.on("change", (fp) => rebuild(fp, "change"))
|
||||||
.on("unlink", (fp) => rebuild(fp, "delete"))
|
.on("unlink", (fp) => rebuild(fp, "delete"))
|
||||||
|
|
||||||
const server = http.createServer(async (req, res) => {
|
|
||||||
await serveHandler(req, res, {
|
|
||||||
public: argv.output,
|
|
||||||
directoryListing: false,
|
|
||||||
})
|
|
||||||
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}`))
|
|
||||||
})
|
|
||||||
server.listen(argv.port)
|
|
||||||
console.log(chalk.cyan(`Started a Quartz server listening at http://localhost:${argv.port}`))
|
|
||||||
console.log("hint: exit with ctrl+c")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async (argv: Argv, version: string) => {
|
export default async (argv: Argv, clientRefresh: () => void) => {
|
||||||
try {
|
try {
|
||||||
await buildQuartz(argv, version)
|
return await buildQuartz(argv, clientRefresh)
|
||||||
} catch {
|
} catch (err) {
|
||||||
console.log(chalk.red("\nExiting Quartz due to a fatal error"))
|
trace("\nExiting Quartz due to a fatal error", err as Error)
|
||||||
process.exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { slug } from "github-slugger"
|
import { slug } from "github-slugger"
|
||||||
import { trace } from "./trace"
|
|
||||||
|
|
||||||
// Quartz Paths
|
// Quartz Paths
|
||||||
// Things in boxes are not actual types but rather sources which these types can be acquired from
|
// Things in boxes are not actual types but rather sources which these types can be acquired from
|
||||||
@ -43,18 +42,6 @@ import { trace } from "./trace"
|
|||||||
// └────────────┤ MD File ├─────┴─────────────────┘
|
// └────────────┤ MD File ├─────┴─────────────────┘
|
||||||
// └─────────┘
|
// └─────────┘
|
||||||
|
|
||||||
const STRICT_TYPE_CHECKS = false
|
|
||||||
const HARD_EXIT_ON_FAIL = false
|
|
||||||
|
|
||||||
function conditionCheck<T>(name: string, label: "pre" | "post", s: T, chk: (x: any) => x is T) {
|
|
||||||
if (STRICT_TYPE_CHECKS && !chk(s)) {
|
|
||||||
trace(`${name} failed ${label}-condition check: ${s} does not pass ${chk.name}`, new Error())
|
|
||||||
if (HARD_EXIT_ON_FAIL) {
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Utility type to simulate nominal types in TypeScript
|
/// Utility type to simulate nominal types in TypeScript
|
||||||
type SlugLike<T> = string & { __brand: T }
|
type SlugLike<T> = string & { __brand: T }
|
||||||
|
|
||||||
@ -102,36 +89,29 @@ export function isFilePath(s: string): s is FilePath {
|
|||||||
|
|
||||||
export function getClientSlug(window: Window): ClientSlug {
|
export function getClientSlug(window: Window): ClientSlug {
|
||||||
const res = window.location.href as ClientSlug
|
const res = window.location.href as ClientSlug
|
||||||
conditionCheck(getClientSlug.name, "post", res, isClientSlug)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCanonicalSlug(window: Window): CanonicalSlug {
|
export function getCanonicalSlug(window: Window): CanonicalSlug {
|
||||||
const res = window.document.body.dataset.slug! as CanonicalSlug
|
const res = window.document.body.dataset.slug! as CanonicalSlug
|
||||||
conditionCheck(getCanonicalSlug.name, "post", res, isCanonicalSlug)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canonicalizeClient(slug: ClientSlug): CanonicalSlug {
|
export function canonicalizeClient(slug: ClientSlug): CanonicalSlug {
|
||||||
conditionCheck(canonicalizeClient.name, "pre", slug, isClientSlug)
|
|
||||||
const { pathname } = new URL(slug)
|
const { pathname } = new URL(slug)
|
||||||
let fp = pathname.slice(1)
|
let fp = pathname.slice(1)
|
||||||
fp = fp.replace(new RegExp(_getFileExtension(fp) + "$"), "")
|
fp = fp.replace(new RegExp(_getFileExtension(fp) + "$"), "")
|
||||||
const res = _canonicalize(fp) as CanonicalSlug
|
const res = _canonicalize(fp) as CanonicalSlug
|
||||||
conditionCheck(canonicalizeClient.name, "post", res, isCanonicalSlug)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canonicalizeServer(slug: ServerSlug): CanonicalSlug {
|
export function canonicalizeServer(slug: ServerSlug): CanonicalSlug {
|
||||||
conditionCheck(canonicalizeServer.name, "pre", slug, isServerSlug)
|
|
||||||
let fp = slug as string
|
let fp = slug as string
|
||||||
const res = _canonicalize(fp) as CanonicalSlug
|
const res = _canonicalize(fp) as CanonicalSlug
|
||||||
conditionCheck(canonicalizeServer.name, "post", res, isCanonicalSlug)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function slugifyFilePath(fp: FilePath): ServerSlug {
|
export function slugifyFilePath(fp: FilePath): ServerSlug {
|
||||||
conditionCheck(slugifyFilePath.name, "pre", fp, isFilePath)
|
|
||||||
fp = _stripSlashes(fp) as FilePath
|
fp = _stripSlashes(fp) as FilePath
|
||||||
const withoutFileExt = fp.replace(new RegExp(_getFileExtension(fp) + "$"), "")
|
const withoutFileExt = fp.replace(new RegExp(_getFileExtension(fp) + "$"), "")
|
||||||
let slug = withoutFileExt
|
let slug = withoutFileExt
|
||||||
@ -145,7 +125,6 @@ export function slugifyFilePath(fp: FilePath): ServerSlug {
|
|||||||
slug = slug.replace(/_index$/, "index")
|
slug = slug.replace(/_index$/, "index")
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionCheck(slugifyFilePath.name, "post", slug, isServerSlug)
|
|
||||||
return slug as ServerSlug
|
return slug as ServerSlug
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,13 +144,11 @@ export function transformInternalLink(link: string): RelativeURL {
|
|||||||
|
|
||||||
let joined = joinSegments(_stripSlashes(prefix), _stripSlashes(fp))
|
let joined = joinSegments(_stripSlashes(prefix), _stripSlashes(fp))
|
||||||
const res = (_addRelativeToStart(joined) + anchor) as RelativeURL
|
const res = (_addRelativeToStart(joined) + anchor) as RelativeURL
|
||||||
conditionCheck(transformInternalLink.name, "post", res, isRelativeURL)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve /a/b/c to ../../
|
// resolve /a/b/c to ../../
|
||||||
export function pathToRoot(slug: CanonicalSlug): RelativeURL {
|
export function pathToRoot(slug: CanonicalSlug): RelativeURL {
|
||||||
conditionCheck(pathToRoot.name, "pre", slug, isCanonicalSlug)
|
|
||||||
let rootPath = slug
|
let rootPath = slug
|
||||||
.split("/")
|
.split("/")
|
||||||
.filter((x) => x !== "")
|
.filter((x) => x !== "")
|
||||||
@ -179,15 +156,11 @@ export function pathToRoot(slug: CanonicalSlug): RelativeURL {
|
|||||||
.join("/")
|
.join("/")
|
||||||
|
|
||||||
const res = _addRelativeToStart(rootPath) as RelativeURL
|
const res = _addRelativeToStart(rootPath) as RelativeURL
|
||||||
conditionCheck(pathToRoot.name, "post", res, isRelativeURL)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveRelative(current: CanonicalSlug, target: CanonicalSlug): RelativeURL {
|
export function resolveRelative(current: CanonicalSlug, target: CanonicalSlug): RelativeURL {
|
||||||
conditionCheck(resolveRelative.name, "pre", current, isCanonicalSlug)
|
|
||||||
conditionCheck(resolveRelative.name, "pre", target, isCanonicalSlug)
|
|
||||||
const res = joinSegments(pathToRoot(current), target) as RelativeURL
|
const res = joinSegments(pathToRoot(current), target) as RelativeURL
|
||||||
conditionCheck(resolveRelative.name, "post", res, isRelativeURL)
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
|
|||||||
|
|
||||||
// embed cases
|
// embed cases
|
||||||
if (value.startsWith("!")) {
|
if (value.startsWith("!")) {
|
||||||
const ext: string | undefined = path.extname(fp).toLowerCase()
|
const ext: string = path.extname(fp).toLowerCase()
|
||||||
const url = slugifyFilePath(fp as FilePath) + ext
|
const url = slugifyFilePath(fp as FilePath) + ext
|
||||||
if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg"].includes(ext)) {
|
if ([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg"].includes(ext)) {
|
||||||
const dims = alias ?? ""
|
const dims = alias ?? ""
|
||||||
@ -218,8 +218,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
|
|||||||
type: "html",
|
type: "html",
|
||||||
value: `<iframe src="${url}"></iframe>`,
|
value: `<iframe src="${url}"></iframe>`,
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ext === "") {
|
||||||
// TODO: this is the node embed case
|
// TODO: note embed
|
||||||
}
|
}
|
||||||
// otherwise, fall through to regular link
|
// otherwise, fall through to regular link
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@ export async function emitContent(ctx: BuildCtx, content: ProcessedContent[]) {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
trace(`Failed to emit from plugin \`${emitter.name}\``, err as Error)
|
trace(`Failed to emit from plugin \`${emitter.name}\``, err as Error)
|
||||||
throw err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ export function createFileParser(ctx: BuildCtx, fps: FilePath[]) {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
trace(`\nFailed to process \`${fp}\``, err as Error)
|
trace(`\nFailed to process \`${fp}\``, err as Error)
|
||||||
throw err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import chalk from "chalk"
|
import chalk from "chalk"
|
||||||
|
import process from "process"
|
||||||
|
|
||||||
const rootFile = /.*at file:/
|
const rootFile = /.*at file:/
|
||||||
export function trace(msg: string, err: Error) {
|
export function trace(msg: string, err: Error) {
|
||||||
@ -28,4 +29,5 @@ export function trace(msg: string, err: Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user