From 6bec19265fcd5093b81f30b8c4d91da5ebe39c11 Mon Sep 17 00:00:00 2001 From: Steve Landey Date: Wed, 11 Sep 2024 14:08:27 -0700 Subject: [PATCH] WIP --- bun.lockb | Bin 309471 -> 309263 bytes package.json | 4 ++- src/engine/executeConfig.ts | 9 ++++-- src/input/fileExtensions.ts | 51 ++++++++++++++++++++++----------- src/input/parseFile.ts | 31 ++++++++++++++++---- src/plugins/autoTitlePlugin.ts | 7 ++--- src/renderers/htmlRenderer.ts | 1 + src/types.ts | 13 ++++++--- src/utils/astUtils.ts | 14 ++++----- src/utils/djotUtils.ts | 10 +------ src/utils/pathUtils.ts | 4 +++ yarn.lock | 6 ++-- 12 files changed, 98 insertions(+), 52 deletions(-) diff --git a/bun.lockb b/bun.lockb index 7a671a5e225d498c7ae21a7ab80996ce4f75662b..bcd60348ac737a3e7e06e137866711b341874fae 100755 GIT binary patch delta 20460 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 diff --git a/package.json b/package.json index a556042..3b90812 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ }, "dependencies": { "@djot/djot": "^0.3.1", + "@types/mdast": "^4.0.4", "argparse": "^2.0.1", "fast-glob": "^3.3.2", "gluegun": "^5.2.0", @@ -49,7 +50,8 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.0", "remark-stringify": "^11.0.0", - "shiki": "^1.14.1" + "shiki": "^1.14.1", + "unified": "^11.0.5" }, "devDependencies": { "@djockey/linkmapper-typedoc": "^0.0.7", diff --git a/src/engine/executeConfig.ts b/src/engine/executeConfig.ts index 1a2539f..eec9645 100644 --- a/src/engine/executeConfig.ts +++ b/src/engine/executeConfig.ts @@ -48,8 +48,13 @@ export async function readDocSet( ): Promise { const logCollector = logCollectorParent.getChild("Parsing documents"); - const parsePromises = config.fileList.map((path_) => - parseFile(config.input_dir, path_, config, logCollector) + if (!config.fileList.length) { + throw new Error("No files"); + } + + const parsePromises = config.fileList.map( + async (path_) => + await parseFile(config.input_dir, path_, config, logCollector) ); const docs = (await Promise.all(parsePromises)).filter((doc) => !!doc); diff --git a/src/input/fileExtensions.ts b/src/input/fileExtensions.ts index c04e601..044132f 100644 --- a/src/input/fileExtensions.ts +++ b/src/input/fileExtensions.ts @@ -8,35 +8,52 @@ import { export function getExtensionForInputFormat(fmt: DjockeyInputFormat): string[] { switch (fmt) { case "gfm": - return ["md", "markdown"]; + return [".md", ".markdown"]; case "djot": - return ["djot", "dj"]; + return [".djot", ".dj"]; case "myst": - return ["md"]; + return [".myst.md", ".md"]; + case "commonmark": + return [".common.md", ".md", ".markdown"]; } } -export function getInputFormatForFileExtension( - ext: string, +export function getInputFormatForFileName( + filename: string, config: DjockeyConfig, frontMatter: Record ): DjockeyInputFormat | null { - const bareExt = ext[0] === "." ? ext.slice(1) : ext; - const defaultMarkdownVariant: MarkdownVariant = (frontMatter.md_variant as MarkdownVariant | undefined) ?? config.default_markdown_variant; - switch (bareExt) { - case "dj": - return "djot"; - case "djot": - return "djot"; - case "md": - return defaultMarkdownVariant; - case "markdown": + for (const fmt of ALL_INPUT_FORMATS) { + for (const ext of getExtensionForInputFormat(fmt)) { + // Double-extensions disambiguate between Markdown formats. + if (ext.split(".").length > 2 && filename.endsWith(ext)) { + return fmt; + } + } + } + + // If we didn't find a totally unambiguous extension, try Markdown. + const mdExts = [".md", ".markdown"]; + for (const ext of mdExts) { + if (filename.endsWith(ext)) { return defaultMarkdownVariant; - default: - return null; + } } + + // Otherwise, try everything else. + for (const fmt of ALL_INPUT_FORMATS) { + for (const ext of getExtensionForInputFormat(fmt)) { + if (filename.endsWith(ext)) { + return fmt; + } + } + } + + console.error("Can't figure out format for", filename); + + return null; } diff --git a/src/input/parseFile.ts b/src/input/parseFile.ts index f9ca4de..3e8c091 100644 --- a/src/input/parseFile.ts +++ b/src/input/parseFile.ts @@ -2,15 +2,18 @@ import fs from "fs"; import path from "path"; import { basename } from "path"; -import yaml from "js-yaml"; import { fromPandoc, parse } from "@djot/djot"; +import { mystParse } from "myst-parser"; +import remarkParse from "remark-parse"; +import remarkGfm from "remark-gfm"; +import { unified } from "unified"; +import yaml from "js-yaml"; + import { DjockeyConfig, DjockeyDoc, PolyglotDoc } from "../types.js"; import { getPandocAST } from "../pandoc.js"; -import { getInputFormatForFileExtension } from "./fileExtensions.js"; +import { getInputFormatForFileName } from "./fileExtensions.js"; import { LogCollector } from "../utils/logUtils.js"; -import { fsext, fsname, fssplit, refjoin } from "../utils/pathUtils.js"; - -import { mystParse } from "myst-parser"; +import { fsbase, fsext, fsname, fssplit, refjoin } from "../utils/pathUtils.js"; function removeExtensionFromPath(path_: string): string { return path_.slice(0, path_.length - path.parse(path_).ext.length); @@ -45,8 +48,17 @@ export async function parseFile( let polyglotDoc: PolyglotDoc | undefined; - switch (getInputFormatForFileExtension(fsext(fsPath), config, frontMatter)) { + logCollector.warning( + `${getInputFormatForFileName( + fsbase(fsPath), + config, + frontMatter + )} ${fsPath}` + ); + + switch (getInputFormatForFileName(fsbase(fsPath), config, frontMatter)) { case "djot": + console.log("Parse", fsbase(fsPath), "as djot"); polyglotDoc = { kind: "djot", value: parse(text, { @@ -56,10 +68,17 @@ export async function parseFile( }; break; case "gfm": + console.log("Parse", fsbase(fsPath), "as gfm"); const ast = getPandocAST(fsPath); polyglotDoc = { kind: "djot", value: fromPandoc(ast as any) }; break; + case "commonmark": + console.log("Parse", fsbase(fsPath), "as gfm"); + const file = await unified().use(remarkParse).use(remarkGfm).process(); + console.log(file); + break; case "myst": + console.log("Parse", fsbase(fsPath), "as myst"); polyglotDoc = { kind: "mdast", value: mystParse(text) }; console.log(yaml.dump(polyglotDoc.value)); break; diff --git a/src/plugins/autoTitlePlugin.ts b/src/plugins/autoTitlePlugin.ts index 995be0f..3452579 100644 --- a/src/plugins/autoTitlePlugin.ts +++ b/src/plugins/autoTitlePlugin.ts @@ -1,16 +1,15 @@ import { Heading } from "@djot/djot"; import { visit, EXIT } from "unist-util-visit"; -import mdast from "mdast"; import { applyFilter } from "../engine/djotFiltersPlus.js"; import { DjockeyDoc, DjockeyPlugin } from "../types.js"; -import { djotASTToText, mystASTToText } from "../utils/djotUtils.js"; +import { djotASTToText } from "../utils/djotUtils.js"; import { LogCollector } from "../utils/logUtils.js"; -import { mystParse } from "myst-parser"; import { djotASTToMystAST_Inline, mystASTToDjotAST_Inline, } from "../utils/astUtils.js"; +import { toString } from "mdast-util-to-string"; export class AutoTitlePlugin implements DjockeyPlugin { name = "Auto Titler"; @@ -40,7 +39,7 @@ export class AutoTitlePlugin implements DjockeyPlugin { break; case "mdast": visit(doc.docs.content.value, "heading", (node) => { - doc.title = mystASTToText(node as mdast.Heading); + doc.title = toString(node); doc.titleASTDjot = mystASTToDjotAST_Inline(node); doc.titleASTMyst = node; return EXIT; diff --git a/src/renderers/htmlRenderer.ts b/src/renderers/htmlRenderer.ts index 590d71d..012f46a 100644 --- a/src/renderers/htmlRenderer.ts +++ b/src/renderers/htmlRenderer.ts @@ -229,6 +229,7 @@ export class HTMLRenderer implements DjockeyRenderer { urlLists: filteredURLListsAsURLs, }); + console.log("Write to", outputFSPath); await writeFile(outputFSPath, outputPage); } } diff --git a/src/types.ts b/src/types.ts index 7fe2e5d..c49d5ad 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,7 +9,7 @@ export interface LinkMappingConfig { url_root: string; } -export type MarkdownVariant = "gfm" | "myst"; +export type MarkdownVariant = "gfm" | "myst" | "commonmark"; export interface DjockeyConfig { input_dir: string; @@ -61,7 +61,7 @@ export interface DjockeyConfigResolved extends DjockeyConfig { rootPath: string; fileList: string[]; url_root: string; - default_markdown_variant: "gfm" | "myst"; + default_markdown_variant: "gfm" | "myst" | "commonmark"; link_mappings: LinkMappingConfig[]; } @@ -96,8 +96,13 @@ export interface DjockeyDoc { } // These correspond to pandoc formats. Keep these two lines in sync. -export type DjockeyInputFormat = "djot" | "gfm" | "myst"; -export const ALL_INPUT_FORMATS: DjockeyInputFormat[] = ["djot", "gfm", "myst"]; +export type DjockeyInputFormat = "djot" | "gfm" | "myst" | "commonmark"; +export const ALL_INPUT_FORMATS: DjockeyInputFormat[] = [ + "djot", + "gfm", + "myst", + "commonmark", +]; // Keep these two lines in sync. export type DjockeyOutputFormat = "html" | "gfm"; diff --git a/src/utils/astUtils.ts b/src/utils/astUtils.ts index ef2de17..03ef0dc 100644 --- a/src/utils/astUtils.ts +++ b/src/utils/astUtils.ts @@ -1,10 +1,12 @@ import { Block, Heading, Inline } from "@djot/djot"; import { Parent, PhrasingContent } from "mdast"; +import unist from "unist"; import { visit } from "unist-util-visit"; +import { toString } from "mdast-util-to-string"; import { applyFilter } from "../engine/djotFiltersPlus.js"; import { DjockeyDoc, PolyglotDoc, PolyglotDoc_MDAST } from "../types.js"; -import { djotASTToText, mystASTToText } from "./djotUtils.js"; +import { djotASTToText } from "./djotUtils.js"; export function getDoesDocHaveContent(doc: PolyglotDoc): boolean { switch (doc.kind) { @@ -43,14 +45,12 @@ export function getFirstHeadingIsAlreadyDocumentTitle( return didFindNode; } -export function mystASTToDjotAST_Inline(mystRoot: Parent): Inline[] { - return [{ tag: "str", text: mystASTToText(mystRoot) }]; +export function mystASTToDjotAST_Inline(root: unist.Parent): Inline[] { + return [{ tag: "str", text: toString(root) }]; } -export function mystASTToDjotAST_Block(mystRoot: Parent): Block[] { - return [ - { tag: "para", children: [{ tag: "str", text: mystASTToText(mystRoot) }] }, - ]; +export function mystASTToDjotAST_Block(root: unist.Parent): Block[] { + return [{ tag: "para", children: [{ tag: "str", text: toString(root) }] }]; } export function djotASTToMystAST_Inline(djotRoot: Inline[]): PhrasingContent[] { diff --git a/src/utils/djotUtils.ts b/src/utils/djotUtils.ts index eacf849..3918168 100644 --- a/src/utils/djotUtils.ts +++ b/src/utils/djotUtils.ts @@ -7,10 +7,10 @@ import { isBlock, } from "@djot/djot"; import mdast from "mdast"; +import unist from "unist"; import { visit } from "unist-util-visit"; import { processAllNodes } from "../engine/djotFiltersPlus.js"; -import { MystDoc } from "../types.js"; export function getHasClass(node: HasAttributes, cls: string): boolean { if (!node.attributes || !node.attributes["class"]) return false; @@ -58,14 +58,6 @@ export function djotASTToText(children: Block[]) { return result.join(""); } -export function mystASTToText(root: mdast.Parent) { - const result = new Array(); - visit(root, "text", (node) => { - result.push((node as mdast.Text).value); - }); - return result.join(""); -} - export function djotASTToTextWithLineBreaks(children: Block[]) { const result = new Array(); diff --git a/src/utils/pathUtils.ts b/src/utils/pathUtils.ts index 4f02bb9..357dc61 100644 --- a/src/utils/pathUtils.ts +++ b/src/utils/pathUtils.ts @@ -127,6 +127,10 @@ export function fsname(s: string): string { return path.parse(s).name; } +export function fsbase(s: string): string { + return path.parse(s).base; +} + export function fsext(s: string): string { return path.parse(s).ext; } diff --git a/yarn.lock b/yarn.lock index d99d156..3f6233e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1396,7 +1396,7 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^4.0.0": +"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.4": version: 4.0.4 resolution: "@types/mdast@npm:4.0.4" dependencies: @@ -2825,6 +2825,7 @@ __metadata: "@types/js-yaml": ^4.0.9 "@types/log-update": ^3.1.0 "@types/lunr": ^2.3.7 + "@types/mdast": ^4.0.4 "@types/micromatch": ^4.0.9 "@types/node": ^22.4.0 "@types/nunjucks": ^3.2.6 @@ -2856,6 +2857,7 @@ __metadata: ts-jest: ^29.2.5 typedoc: ^0.26.6 typescript: ^5.5.4 + unified: ^11.0.5 bin: djockey: ./dist/cli.js languageName: unknown @@ -7555,7 +7557,7 @@ __metadata: languageName: node linkType: hard -"unified@npm:^11.0.0": +"unified@npm:^11.0.0, unified@npm:^11.0.5": version: 11.0.5 resolution: "unified@npm:11.0.5" dependencies: