From 003e6e20730b8e9f70b631757cf5f75218a78ecc Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:05:33 -0400 Subject: [PATCH 1/7] add TS-native EDSL for building Pandoc JSON AST --- src/core/pandoc/json.ts | 580 +++++++++++++++++++++++++++++++++++++++ src/core/pandoc/table.ts | 38 +++ 2 files changed, 618 insertions(+) create mode 100644 src/core/pandoc/json.ts create mode 100644 src/core/pandoc/table.ts diff --git a/src/core/pandoc/json.ts b/src/core/pandoc/json.ts new file mode 100644 index 00000000000..dbd5d22d175 --- /dev/null +++ b/src/core/pandoc/json.ts @@ -0,0 +1,580 @@ +/* + * json.ts + * + * Copyright (C) 2025 Posit Software, PBC + */ + +// An EDSL for building Pandoc AST JSON + +// utilities +export type Attr = [string, string[], string[][]]; +export type Caption = [null, Block[]]; +export type Alignment = { "t": "AlignLeft" } | { "t": "AlignCenter" } | { + "t": "AlignRight"; +}; +export type ColWidth = { "t": "ColWidthDefault" } | { + "t": "ColWidth"; + c: number; +}; +export type ColSpec = [Alignment, ColWidth]; + +export type TableHead = [Attr, TableRow[]]; +export type TableRow = [Attr, TableCell[]]; +export type TableCell = [Attr, Alignment, number, number, Block[]]; + +export type TableBody = [Attr, number, TableRow[], TableRow[]]; +export type TableFoot = [Attr, TableRow[]]; +export type Citation = { + citationId: string; + citationPrefix: Inline[]; + citationSuffix: Inline[]; + citationMode: { "t": "AuthorInText" | "SuppressAuthor" | "NormalCitation" }; + citationNoteNum: number; + citationHash: number; +}; + +// Inlines +export type Cite = { + "t": "Cite"; + "c": [Citation[], Inline[]]; +}; + +export type Code = { + "t": "Code"; + "c": [Attr, string]; +}; + +export type Emph = { + "t": "Emph"; + "c": Inline[]; +}; + +export type Image = { + "t": "Image"; + "c": [Attr, Inline[], [string, string]]; +}; + +export type LineBreak = { "t": "LineBreak" }; + +export type Link = { + "t": "Link"; + "c": [Attr, Inline[], [string, string]]; +}; + +export type Math = { + "t": "Math"; + "c": [{ "t": "DisplayMath" | "InlineMath" }, string]; +}; + +export type Note = { + "t": "Note"; + "c": Block[]; +}; + +export type Quoted = { + "t": "Quoted"; + "c": [{ "t": "DoubleQuote" | "SingleQuote" }, Inline[]]; +}; + +export type RawInline = { + "t": "RawInline"; + "c": [string, string]; +}; + +export type SmallCaps = { + "t": "SmallCaps"; + "c": Inline[]; +}; + +export type SoftBreak = { "t": "SoftBreak" }; + +export type Space = { "t": "Space" }; + +export type Span = { + "t": "Span"; + "c": [Attr, ...Span[]]; +}; + +export type Str = { + "t": "Str"; + "c": string; +}; + +export type Strikeout = { + "t": "Strikeout"; + "c": Inline[]; +}; + +export type Strong = { + "t": "Strong"; + "c": Inline[]; +}; + +export type Subscript = { + "t": "Subscript"; + "c": Inline[]; +}; + +export type Superscript = { + "t": "Superscript"; + "c": Inline[]; +}; + +export type Underline = { + "t": "Underline"; + "c": Inline[]; +}; + +export type Inline = + | Cite + | Code + | Emph + | Image + | LineBreak + | Link + | Math + | Note + | Quoted + | RawInline + | SmallCaps + | SoftBreak + | Space + | Span + | Str + | Strikeout + | Strong + | Subscript + | Superscript + | Underline; + +// Define a type for inline elements that have c: Inline[] structure +type SimpleInlineType = + | "Emph" + | "SmallCaps" + | "Strikeout" + | "Strong" + | "Subscript" + | "Superscript" + | "Underline"; + +// Type guard to check if an inline type is a SimpleInlineType +type SimpleInline = Extract; + +// Blocks +export type BlockQuote = { + "t": "BlockQuote"; + "c": Block[]; +}; + +export type BulletList = { + "t": "BulletList"; + "c": Block[][]; +}; + +export type CodeBlock = { + "t": "CodeBlock"; + "c": [Attr, string]; +}; + +export type DefinitionList = { + "t": "DefinitionList"; + "c": [Inline[], Block[]][]; +}; + +export type Div = { + "t": "Div"; + "c": [Attr, ...Block[]]; +}; + +export type Figure = { + "t": "Figure"; + "c": [Attr, [null, Block[]], Block[]]; +}; + +export type Header = { + "t": "Header"; + "c": [number, Attr, Inline[]]; +}; + +export type HorizontalRule = { + "t": "HorizontalRule"; +}; + +export type LineBlock = { + t: "LineBlock"; + c: Inline[][]; +}; + +export type OrderedList = { + "t": "OrderedList"; + "c": [[number, { + "t": + | "DefaultStyle" + | "Example" + | "Decimal" + | "LowerRoman" + | "UpperRoman" + | "LowerAlpha" + | "UpperAlpha"; + }, { "t": "DefaultDelim" | "Period" | "Paren" }], Block[][]]; +}; + +export type Para = { + "t": "Para"; + "c": Inline[]; +}; + +export type Plain = { + "t": "Plain"; + "c": Inline[]; +}; + +export type RawBlock = { + "t": "RawBlock"; + "c": [string, string]; +}; + +export type Table = { + "t": "Table"; + "c": [ + Attr, + Caption, + ColSpec[], + TableHead, + TableBody[], + TableFoot, + ]; +}; + +export type Block = + | BlockQuote + | BulletList + | CodeBlock + | DefinitionList + | Div + | Figure + | Header + | HorizontalRule + | LineBlock + | OrderedList + | Para + | Plain + | RawBlock + | Table; + +export type Pandoc = { + "pandoc-api-version": [number, number, number]; + meta: Record; + blocks: Block[]; +}; + +// inline constructors + +export function attr( + id?: string, + classes?: string[], + keyvals?: Record, +): Attr { + const keyvalsArray: string[][] = []; + if (keyvals) { + for (const [key, value] of Object.entries(keyvals)) { + keyvalsArray.push([key, value]); + } + } + return [id || "", classes || [], keyvalsArray]; +} + +const makeInlinesNode = (name: T) => +( + content: Inline[], +): SimpleInline => { + return { + t: name, + c: content, + } as SimpleInline; +}; +const ensureAttr = (attr?: Attr): Attr => { + if (!attr) { + return ["", [], []]; + } + return attr; +}; + +export const cite = (citations: Citation[], content: Inline[]): Cite => ({ + t: "Cite", + c: [citations, content], +}); + +export const code = (content: string, attr?: Attr): Code => ({ + t: "Code", + c: [ensureAttr(attr), content], +}); + +export const emph = makeInlinesNode("Emph"); + +export const image = ( + content: Inline[], + url: string, + description = "", + attr?: Attr, +): Image => ({ + t: "Image", + c: [ensureAttr(attr), content, [url, description]], +}); + +export const lineBreak = (): LineBreak => ({ + t: "LineBreak", +}); + +export const link = ( + attr: Attr, + content: Inline[], + url: string, + description = "", +): Link => ({ + t: "Link", + c: [attr, content, [url, description]], +}); + +export const math = ( + type: "DisplayMath" | "InlineMath", + content: string, +): Math => ({ + t: "Math", + c: [{ t: type }, content], +}); + +export const note = (content: Block[]): Note => ({ + t: "Note", + c: content, +}); + +export const quoted = ( + type: "DoubleQuote" | "SingleQuote", + content: Inline[], +): Quoted => ({ + t: "Quoted", + c: [{ t: type }, content], +}); + +export const rawInline = (format: string, content: string): RawInline => ({ + t: "RawInline", + c: [format, content], +}); + +export const smallCaps = makeInlinesNode("SmallCaps"); + +export const softBreak = (): SoftBreak => ({ + t: "SoftBreak", +}); + +export const space = (): Space => ({ + t: "Space", +}); + +export const span = (attr: Attr, content: Span[]): Span => ({ + t: "Span", + c: [attr, ...content], +}); + +export const str = (content: string): Str => ({ + t: "Str", + c: content, +}); + +export const strikeout = makeInlinesNode("Strikeout"); + +export const strong = makeInlinesNode("Strong"); + +export const subscript = makeInlinesNode("Subscript"); + +export const superscript = makeInlinesNode("Superscript"); + +export const underline = makeInlinesNode("Underline"); + +// block constructors + +export const blockQuote = (content: Block[]): BlockQuote => ({ + t: "BlockQuote", + c: content, +}); + +export const bulletList = (content: Block[][]): BulletList => ({ + t: "BulletList", + c: content, +}); + +export const codeBlock = (content: string, attr?: Attr): CodeBlock => ({ + t: "CodeBlock", + c: [ensureAttr(attr), content], +}); + +export const definitionList = ( + content: [Inline[], Block[]][], +): DefinitionList => ({ + t: "DefinitionList", + c: content, +}); + +export const div = (content: Block[], attr?: Attr): Div => ({ + t: "Div", + c: [ensureAttr(attr), ...content], +}); + +export const figure = ( + caption: Caption, + content: Block[], + attr?: Attr, +): Figure => ({ + t: "Figure", + c: [ensureAttr(attr), caption, content], +}); + +export const header = ( + level: number, + content: Inline[], + attr?: Attr, +): Header => ({ + t: "Header", + c: [level, ensureAttr(attr), content], +}); + +export const horizontalRule = (): HorizontalRule => ({ + t: "HorizontalRule", +}); + +export const lineBlock = (content: Inline[][]): LineBlock => ({ + t: "LineBlock", + c: content, +}); + +export const orderedList = ( + start: number, + style: + | "DefaultStyle" + | "Example" + | "Decimal" + | "LowerRoman" + | "UpperRoman" + | "LowerAlpha" + | "UpperAlpha", + delimiter: "DefaultDelim" | "Period" | "Paren", + content: Block[][], +): OrderedList => ({ + t: "OrderedList", + c: [[start, { t: style }, { t: delimiter }], content], +}); + +export const para = (content: Inline[]): Para => ({ + t: "Para", + c: content, +}); + +export const plain = (content: Inline[]): Plain => ({ + t: "Plain", + c: content, +}); + +export const rawBlock = (format: string, content: string): RawBlock => ({ + t: "RawBlock", + c: [format, content], +}); + +export const table = ( + caption: Caption, + colSpec: ColSpec[], + head: TableHead, + body: TableBody[], + foot?: TableFoot, + attr?: Attr, +): Table => ({ + t: "Table", + c: [ + ensureAttr(attr), + caption, + colSpec, + head, + body, + foot || tableFoot([], ensureAttr()), + ], +}); + +export const colspec = ( + alignment: "AlignLeft" | "AlignCenter" | "AlignRight", + colWidth: "ColWidthDefault" | { t: "ColWidth"; c: number }, +): ColSpec => { + const alignmentObj: Alignment = { t: alignment }; + const colWidthObj: ColWidth = colWidth === "ColWidthDefault" + ? { t: "ColWidthDefault" } + : { t: "ColWidth", c: colWidth.c }; + return [ + alignmentObj, + colWidthObj, + ]; +}; + +export const caption = (content: Block[]): Caption => [null, content]; + +export const tableHead = (rows: TableRow[], attr?: Attr): TableHead => [ + ensureAttr(attr), + rows, +]; + +export const tableRow = (cells: TableCell[], attr?: Attr): TableRow => [ + ensureAttr(attr), + cells, +]; + +export const tableCell = ( + content: Block[], + alignment: "AlignLeft" | "AlignCenter" | "AlignRight" = "AlignLeft", + colspan = 1, + rowspan = 1, + attr?: Attr, +): TableCell => [ + ensureAttr(attr), + { t: alignment }, + colspan, + rowspan, + content, +]; + +export const tableBody = ( + body: TableRow[], + head?: TableRow[], + rowHeadColumns: number = 0, + attr?: Attr, +): TableBody => [ensureAttr(attr), rowHeadColumns, body, head || []]; + +export const tableFoot = (rows: TableRow[], attr?: Attr): TableFoot => [ + ensureAttr(attr), + rows, +]; + +export const citation = ( + citationId: string, + citationPrefix: Inline[], + citationSuffix: Inline[], + citationMode: + | "AuthorInText" + | "SuppressAuthor" + | "NormalCitation", + citationNoteNum: number, + citationHash: number, +): Citation => ({ + citationId, + citationPrefix, + citationSuffix, + citationMode: { t: citationMode }, + citationNoteNum, + citationHash, +}); + +export const pandoc = ( + meta: Record, + blocks: Block[], +): Pandoc => ({ + "pandoc-api-version": [1, 23, 1], + meta, + blocks, +}); diff --git a/src/core/pandoc/table.ts b/src/core/pandoc/table.ts new file mode 100644 index 00000000000..44ef0335cdb --- /dev/null +++ b/src/core/pandoc/table.ts @@ -0,0 +1,38 @@ +/* + * table.ts + * + * Helpers for creating Pandoc AST tables from JS objects + * + * Copyright (C) 2025 Posit Software, PBC + */ + +import * as Pandoc from "./json.ts"; + +export const fromObjects = ( + objects: Record[], + keys?: string[], + colSpecs?: Pandoc.ColSpec[], +): Pandoc.Table => { + if (keys === undefined) { + keys = Object.keys(objects[0]); + } + const header = Pandoc.tableHead([ + Pandoc.tableRow( + keys.map((key) => Pandoc.tableCell([Pandoc.plain([Pandoc.str(key)])])), + ), + ]); + const result = Pandoc.table( + Pandoc.caption([]), + colSpecs ?? keys.map((_) => Pandoc.colspec("AlignLeft", "ColWidthDefault")), + header, + [Pandoc.tableBody( + objects.map((object) => + Pandoc.tableRow(keys.map((key) => { + const value = object[key]; + return Pandoc.tableCell(value, "AlignLeft"); + })) + ), + )], + ); + return result; +}; From 0f1bfa60c5481e4b381ca841c8ee9b35536c5e74 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:06:03 -0400 Subject: [PATCH 2/7] logPandoc, logPandocJSON - use pandoc -t ansi to produce nicely-formatted output --- src/core/log.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/core/log.ts b/src/core/log.ts index 558b15756a2..a7228f80a90 100644 --- a/src/core/log.ts +++ b/src/core/log.ts @@ -19,6 +19,9 @@ import { lines } from "./text.ts"; import { debug, error, getLogger, setup, warning } from "../deno_ral/log.ts"; import { asErrorEx, InternalError } from "./lib/error.ts"; import { onCleanup } from "./cleanup.ts"; +import { execProcess } from "./process.ts"; +import { pandocBinaryPath } from "./resources.ts"; +import { Block, pandoc } from "./pandoc/json.ts"; export type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR"; @@ -459,3 +462,33 @@ const levelMap: Record< warning: "WARN", error: "ERROR", }; + +export async function logPandocJson( + blocks: Block[], +) { + const src = JSON.stringify(pandoc({}, blocks), null, 2); + return logPandoc(src, "json"); +} + +export async function logPandoc( + src: string, + format: string = "markdown", +) { + const cols = Deno.consoleSize().columns; + const result = await execProcess({ + cmd: [ + pandocBinaryPath(), + "-f", + format, + "-t", + "ansi", + `--columns=${cols}`, + ], + stdout: "piped", + }, src); + if (result.code !== 0) { + error(result.stderr); + } else { + log.info(result.stdout); + } +} From 7fa9561253b9afe99d45bc5864b28fa9b9ba151a Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:06:40 -0400 Subject: [PATCH 3/7] use pandoc formatted ansi output --- package/src/cmd/pkg-cmd.ts | 5 +-- .../src/common/archive-binary-dependencies.ts | 23 ++++++------- package/src/common/config.ts | 32 +++++++++++++++++++ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/package/src/cmd/pkg-cmd.ts b/package/src/cmd/pkg-cmd.ts index da91df980e6..2c5edf15039 100644 --- a/package/src/cmd/pkg-cmd.ts +++ b/package/src/cmd/pkg-cmd.ts @@ -7,7 +7,7 @@ import { Command } from "cliffy/command/mod.ts"; import { join } from "../../../src/deno_ral/path.ts"; -import { printConfiguration } from "../common/config.ts"; +import { configurationAST } from "../common/config.ts"; import { Configuration, @@ -15,6 +15,7 @@ import { kValidOS, readConfiguration, } from "../common/config.ts"; +import { logPandocJson } from "../../../src/core/log.ts"; export const kLogLevel = "logLevel"; export const kVersion = "setVersion"; @@ -49,7 +50,7 @@ export function packageCommand(run: (config: Configuration) => Promise) { Deno.env.set("QUARTO_DEBUG", "true"); // Print the configuration - printConfiguration(config); + await logPandocJson(configurationAST(config)); // Run the command await run(config); diff --git a/package/src/common/archive-binary-dependencies.ts b/package/src/common/archive-binary-dependencies.ts index 8082e6e41b3..f4b3ee16c96 100644 --- a/package/src/common/archive-binary-dependencies.ts +++ b/package/src/common/archive-binary-dependencies.ts @@ -5,6 +5,7 @@ */ import { join } from "../../../src/deno_ral/path.ts"; import { info } from "../../../src/deno_ral/log.ts"; +import { logPandoc } from "../../../src/core/log.ts"; import { execProcess } from "../../../src/core/process.ts"; import { Configuration, withWorkingDir } from "./config.ts"; @@ -34,7 +35,7 @@ export function archiveUrl( // Archives dependencies (if they are not present in the archive already) export async function archiveBinaryDependencies(_config: Configuration) { await withWorkingDir(async (workingDir) => { - info(`Updating binary dependencies...\n`); + await logPandoc(`## Updating binary dependencies`); for (const dependency of kDependencies) { await archiveBinaryDependency(dependency, workingDir); @@ -45,7 +46,7 @@ export async function archiveBinaryDependencies(_config: Configuration) { // Archives dependencies (if they are not present in the archive already) export async function checkBinaryDependencies(_config: Configuration) { await withWorkingDir(async (workingDir) => { - info(`Updating binary dependencies...\n`); + await logPandoc(`## Checking binary dependencies`); for (const dependency of kDependencies) { await checkBinaryDependency(dependency, workingDir); @@ -99,10 +100,9 @@ export async function archiveBinaryDependency( dependency: Dependency, workingDir: string, ) { - info(`** ${dependency.name} ${dependency.version} **`); + await logPandoc(`## ${dependency.name} ${dependency.version}\n\nChecking archive status...`, "markdown"); const dependencyBucketPath = `${dependency.bucket}/${dependency.version}`; - info("Checking archive status...\n"); const archive = async ( architectureDependency: ArchitectureDependency, @@ -117,7 +117,7 @@ export async function archiveBinaryDependency( const dependencyAwsPath = `${kBucket}/${dependencyBucketPath}/${platformDep.filename}`; - info(`Checking ${dependencyAwsPath}`); + await logPandoc(`Checking \`${dependencyAwsPath}\``, "markdown"); const response = await s3cmd("ls", [dependencyAwsPath]); if (response?.includes('Unable to locate credentials')) { throw new Error("Unable to locate S3 credentials, please try again."); @@ -126,8 +126,8 @@ export async function archiveBinaryDependency( if (!response) { // This dependency doesn't exist, archive it - info( - `Archiving ${dependencyBucketPath} - ${platformDep.filename}`, + await logPandoc( + `Archiving \`${dependencyBucketPath}\` - ${platformDep.filename}`, ); // Download the file @@ -144,23 +144,18 @@ export async function archiveBinaryDependency( "--acl", "public-read", ]); - - info(`(Reponse): ${result}`); - + info(` (Response): ${result}`); } else { - info(`${dependencyAwsPath} already archived.`); + info(` ${dependencyAwsPath.split("/").slice(-1)[0]} already archived.\n`); } } } }; for (const arch of Object.keys(dependency.architectureDependencies)) { - info(`Archiving ${dependency.name}`); const archDep = dependency.architectureDependencies[arch]; await archive(archDep); } - - info(""); } async function s3cmd(cmd: string, args: string[]) { diff --git a/package/src/common/config.ts b/package/src/common/config.ts index 1eff4ba0f3f..d8f02c5d117 100644 --- a/package/src/common/config.ts +++ b/package/src/common/config.ts @@ -11,6 +11,8 @@ import { info } from "../../../src/deno_ral/log.ts"; import { getEnv } from "../util/utils.ts"; import { os as platformOs } from "../../../src/deno_ral/platform.ts" +import * as Pandoc from "../../../src/core/pandoc/json.ts"; +import { fromObjects } from "../../../src/core/pandoc/table.ts"; // The core configuration for the packaging process export interface Configuration extends PlatformConfiguration { @@ -116,6 +118,36 @@ export function readConfiguration( }; } +export function configurationAST(config: Configuration): Pandoc.Block[] { + const makeObject = ( + obj: { + key: string, + value: string + }, + ) => ({ + "key": [Pandoc.plain([Pandoc.str(obj.key)])], + "value": [Pandoc.plain([Pandoc.code(obj.value)])] + }); + const configTable = fromObjects([ + {key: "OS", value: config.os}, + {key: "Arch", value: config.arch}, + {key: "Version", value: config.version}, + {key: "Cwd", value: Deno.cwd()}, + {key: "Package folder (build source)", value: config.directoryInfo.pkg}, + {key: "Dist folder (output folder)", value: config.directoryInfo.dist}, + {key: "Bin folder", value: config.directoryInfo.bin}, + {key: "Share folder", value: config.directoryInfo.share}, + {key: "Package working folder", value: config.directoryInfo.pkgWorking.root}, + ].map(makeObject), undefined, [ + Pandoc.colspec("AlignLeft", {t: "ColWidth", c: 0.3}), + Pandoc.colspec("AlignLeft", {t: "ColWidth", c: 0.6}), + ]); + return [ + Pandoc.header(2, [Pandoc.str("Configuration:")]), + configTable, + ]; +} + export function printConfiguration(config: Configuration) { info(""); info("******************************************"); From 420cee7bb774dcd9e79720623e36670435345385 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:06:48 -0400 Subject: [PATCH 4/7] bump esbuild --- configuration | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration b/configuration index f3e0658a338..eb7ad7898f5 100644 --- a/configuration +++ b/configuration @@ -16,7 +16,7 @@ export DENO=v1.46.3 export DENO_DOM=v0.1.41-alpha-artifacts export PANDOC=3.6.3 export DARTSASS=1.85.1 -export ESBUILD=0.19.12 +export ESBUILD=0.25.3 export TYPST=0.13.0 From da09ac9cd4535139a337b6a56a6597d19937aa23 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:08:15 -0400 Subject: [PATCH 5/7] deps - dart sass and esbuild --- configuration | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration b/configuration index eb7ad7898f5..744e7520ad8 100644 --- a/configuration +++ b/configuration @@ -15,7 +15,7 @@ export DENO=v1.46.3 # TODO figure out where 0.1.41 apple silicon libs are available export DENO_DOM=v0.1.41-alpha-artifacts export PANDOC=3.6.3 -export DARTSASS=1.85.1 +export DARTSASS=1.87.0 export ESBUILD=0.25.3 export TYPST=0.13.0 From 5f106e83611958f28a219ad83ae6e05e9916b398 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:16:59 -0400 Subject: [PATCH 6/7] set 130 as the columns default if terminal doesn't support querying --- src/core/log.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/log.ts b/src/core/log.ts index a7228f80a90..d3971f31954 100644 --- a/src/core/log.ts +++ b/src/core/log.ts @@ -470,11 +470,20 @@ export async function logPandocJson( return logPandoc(src, "json"); } +const getColumns = () => { + try { + // Catch error in none tty mode: Inappropriate ioctl for device (os error 25) + return Deno.consoleSize().columns ?? 130; + } catch (_error) { + return 130; + } +}; + export async function logPandoc( src: string, format: string = "markdown", ) { - const cols = Deno.consoleSize().columns; + const cols = getColumns(); const result = await execProcess({ cmd: [ pandocBinaryPath(), From b54d67153a8e9ea778c5ab2a71190b09dabccc8d Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Wed, 30 Apr 2025 20:34:22 -0400 Subject: [PATCH 7/7] fallback to old print during configuration --- package/src/cmd/pkg-cmd.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/package/src/cmd/pkg-cmd.ts b/package/src/cmd/pkg-cmd.ts index 2c5edf15039..954eddd5a58 100644 --- a/package/src/cmd/pkg-cmd.ts +++ b/package/src/cmd/pkg-cmd.ts @@ -7,7 +7,7 @@ import { Command } from "cliffy/command/mod.ts"; import { join } from "../../../src/deno_ral/path.ts"; -import { configurationAST } from "../common/config.ts"; +import { configurationAST, printConfiguration } from "../common/config.ts"; import { Configuration, @@ -50,7 +50,11 @@ export function packageCommand(run: (config: Configuration) => Promise) { Deno.env.set("QUARTO_DEBUG", "true"); // Print the configuration - await logPandocJson(configurationAST(config)); + try { + await logPandocJson(configurationAST(config)); + } catch (e) { + printConfiguration(config); + } // Run the command await run(config);