diff --git a/observablehq.config.ts b/observablehq.config.ts index 59b54bdf3..331e43b8f 100644 --- a/observablehq.config.ts +++ b/observablehq.config.ts @@ -16,6 +16,11 @@ export default { root: "docs", output: "docs/.observablehq/dist", title: "Observable Framework", + defaultBlockAttributes: { + "*": { + run: "false" + } + }, pages: [ {name: "What is Framework?", path: "/what-is-framework"}, {name: "Getting started", path: "/getting-started"}, diff --git a/src/config.ts b/src/config.ts index 126445a90..8d73f4ca1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -273,6 +273,7 @@ export function normalizeConfig(spec: ConfigSpec = {}, defaultRoot?: string, wat } const config: Config = { + defaultBlockAttributes: spec.defaultBlockAttributes, // TODO root, output, base, diff --git a/src/markdown.ts b/src/markdown.ts index c736884b8..c39c358b0 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -49,6 +49,7 @@ interface ParseContext { currentLine: number; path: string; params?: Params; + defaultBlockAttributes?: ParseOptions["defaultBlockAttributes"]; } function uniqueCodeId(context: ParseContext, content: string): string { @@ -114,6 +115,8 @@ function makeFenceRenderer(baseRenderer: RenderRule): RenderRule { const {path, params} = context; const token = tokens[idx]; const {tag, attributes} = parseInfo(token.info); + inheritAttributes(attributes, context.defaultBlockAttributes?.[tag]); + inheritAttributes(attributes, context.defaultBlockAttributes?.["*"]); token.info = tag; let html = ""; let source: string | undefined; @@ -141,6 +144,16 @@ function makeFenceRenderer(baseRenderer: RenderRule): RenderRule { }; } +function inheritAttributes(attributes: Record, defaults?: Record): void { + if (defaults) { + for (const key in defaults) { + if (!(key in attributes)) { + attributes[key] = defaults[key]; + } + } + } +} + const CODE_DOLLAR = 36; const CODE_BRACEL = 123; @@ -217,6 +230,7 @@ export interface ParseOptions { header?: Config["header"]; footer?: Config["footer"]; params?: Params; + defaultBlockAttributes?: Record>; } export function createMarkdownIt({ @@ -242,10 +256,10 @@ export function createMarkdownIt({ } export function parseMarkdown(input: string, options: ParseOptions): MarkdownPage { - const {md, path, params} = options; + const {md, path, params, defaultBlockAttributes} = options; const {content, data} = readFrontMatter(input); const code: MarkdownCode[] = []; - const context: ParseContext = {code, startLine: 0, currentLine: 0, path, params}; + const context: ParseContext = {code, startLine: 0, currentLine: 0, path, params, defaultBlockAttributes}; const tokens = md.parse(content, context); const body = md.renderer.render(tokens, md.options, context); // Note: mutates code! const title = data.title !== undefined ? data.title : findTitle(tokens);