Path: blob/main/src/resources/tools/ast-tracing/convert-pandoc-json.js
12922 views
// converts our trace filter's JSON output to a more compact format1// whose diffs are easier to read2//3// this doesn't work on arbitrary pandoc JSON, since we4// treat custom nodes in a particular way56const postProcessStrings = (array) => {7if (array.length === 0) {8return [];9}10const result = [array[0]];11for (const el of array.slice(1)) {12if (13typeof result[result.length - 1] !== "string" ||14typeof el !== "string"15) {16result.push(el);17continue;18}19result[result.length - 1] = result[result.length - 1] + el;20}21if (result.length === 1 && typeof result[0] === "string") {22return result[0];23}24return result;25};2627const convertListAttributes = (listAttr) => ({28start: listAttr[0],29style: listAttr[1].t,30delimiter: listAttr[2].t,31});3233const convertAttr = (attr) =>34`('${attr[0]}', [${attr[1].map((s) => `'${s}'`).join(", ")}], [${attr[2]35.map((s) => `'${s}'`)36.join(", ")}])`;37const convertCitation = (c) => c;3839// FIXME40const convertCaption = (caption) => caption;4142const convertColSpec = (colSpec) => {43const align = colSpec[0].t;44const width = colSpec[1].c;4546return `(${align}, ${width})`;47};4849const convertCell = (cell) => {50return {51t: "TableCell",52attr: convertAttr(cell[0]),53alignment: cell[1].t,54row_span: cell[2],55col_span: cell[3],56content: convert(cell[4]),57};58};5960const convertRow = (row) => {61return {62t: "TableRow",63attr: convertAttr(row[0]),64cells: row[1].map(convertCell),65};66};6768const convertTableHead = (head) => {69return {70t: "TableHead",71attr: convertAttr(head[0]),72rows: head[1].map(convertRow),73};74};7576const convertTableBody = (body) => {77return {78t: "TableBody",79row_head_columns: body[1],80attr: convertAttr(body[0]),81intermediate_head: body[2].map(convertRow),82body: body[3].map(convertRow),83};84};8586const convertTableFoot = (foot) => {87return {88t: "TableFoot",89attr: convertAttr(foot[0]),90rows: foot[1].map(convertRow),91};92};9394const convert = (data) => {95if (Array.isArray(data)) {96return postProcessStrings(data.map(convert).flat());97}98if (typeof data === "object") {99const constMap = {100Space: " ",101Null: null,102SingleQuote: "'",103DoubleQuote: '"',104};105if (constMap[data.t]) {106return constMap[data.t];107}108if (data.t === "Str") return data.c;109if (110[111"BlockQuote",112"BulletList",113"Plain",114"Para",115"Strong",116"Emph",117"Underline",118"Strikeout",119"Quoted",120"SingleQuote",121"Note",122].includes(data.t)123) {124return {125t: data.t,126content: convert(data.c),127};128}129if (130["AlignLeft", "AlignRight", "AlignCenter", "AlignDefault"].includes(131data.t132)133) {134return data.t;135}136if (data.t === "Table") {137return {138t: data.t,139attr: convertAttr(data.c[0]),140caption: convertCaption(data.c[1]),141colspecs: data.c[2].map(convertColSpec),142head: convertTableHead(data.c[3]),143body: data.c[4].map(convertTableBody),144foot: convertTableFoot(data.c[5]),145};146}147if (data.t === "Code") {148return {149t: data.t,150attr: convertAttr(data.c[0]),151text: data.c[1],152};153}154if (data.t === "Cite") {155return {156t: data.t,157content: convert(data.c[1]),158citations: data.c[0].map(convertCitation),159};160}161if (162data.t === "Div" &&163data.c[0][2].find((x) => x[0] === "__quarto_custom_table")164) {165const attributes = Object.fromEntries(data.c[0][2]);166const entry = attributes["__quarto_custom_table"];167// const t = attributes["__quarto_custom_type"];168const customTable = JSON.parse(entry);169return {170customAST: true,171...customTable,172scaffold: convert(data.c.slice(1)),173};174}175if (data.t === "Div" || data.t === "Span") {176return {177t: data.t,178attr: convertAttr(data.c[0]),179content: convert(data.c.slice(1)),180};181}182if (data.t === "Header") {183return {184t: data.t,185level: data.c[0],186attr: convertAttr(data.c[1]),187content: convert(data.c.slice(2)),188};189}190if (data.t === "Link") {191return {192t: data.t,193attr: convertAttr(data.c[0]),194content: convert(data.c[1]),195target: data.c[2][0],196title: data.c[2][1],197};198}199if (data.t === "Image") {200return {201t: data.t,202attr: convertAttr(data.c[0]),203caption: convert(data.c[1]),204src: data.c[2][0],205title: data.c[2][1],206};207}208if (data.t === "CodeBlock") {209return {210t: data.t,211attr: convertAttr(data.c[0]),212text: data.c[1],213};214}215if (data.t === "OrderedList") {216return {217t: data.t,218listAttributes: convertListAttributes(data.c[0]),219content: convert(data.c[1]),220};221}222if (data.t === "MetaInlines" || data.t === "MetaBlocks") {223return postProcessStrings(data.c.map(convert));224}225if (data.t === "MetaBool") {226return data.c;227}228if (data.t === "SoftBreak") {229return "";230}231if (data.t === "LineBreak") {232return "\n";233}234235if (data.t === "MetaString") {236return data.c;237}238if (data.t === "MetaList") {239return postProcessStrings(data.c.map(convert));240}241if (data.t === "MetaMap") {242return convertMeta(data.c);243}244if (data.t === "RawBlock" || data.t === "RawInline") {245return {246t: data.t,247format: data.c[0],248text: data.c[1],249};250}251if (data.t === "Figure") {252return {253t: data.t,254attr: convertAttr(data.c[0]),255content: convert(data.c[2]),256caption: convertCaption(data.c[1]),257};258}259if (data.t === "DefinitionList") {260return {261t: data.t,262content: data.c.map(convert),263};264}265if (data.t === "Math") {266return {267t: data.t,268displayType: data.c[0].t,269text: data.c[1],270};271}272if (data.t === "HorizontalRule") {273return data;274}275throw new Error(`Can't handle type ${data.t}`);276} else if (typeof data === "string") {277return data;278}279return {280name: "<value>",281children: [],282};283};284285const convertMeta = (meta) => {286return Object.fromEntries(287Object.entries(meta).map(([key, value]) => {288return [key, convert(value)];289})290);291};292293export const convertDoc = (doc) => {294return {295meta: convertMeta(doc.meta),296"pandoc-api-version": doc["pandoc-api-version"].join(","),297blocks: doc.blocks.map(convert),298};299};300301302