From 2e4d1e0441d89f8aabda755b72ebe65106bad1f0 Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Sun, 23 Jun 2024 21:53:39 +0200 Subject: [PATCH] Fix tests --- src/odt/OdtToMarkdown.ts | 6 +-- src/odt/markdownNodesUtils.ts | 2 +- src/odt/postprocess/postProcess.ts | 3 +- src/odt/postprocess/rewriteHeaders.ts | 56 ++++++++++++++++++++++++--- src/odt/postprocess/trimParagraphs.ts | 2 +- src/utils/idParsers.ts | 2 +- test/odt_md/bullets.md | 6 +-- test/odt_md/confluence.md | 18 +++++---- test/odt_md/example-document.md | 36 ++++++++--------- test/odt_md/header-link.md | 2 + test/odt_md/issue-432.md | 2 +- test/odt_md/issue-435-436.md | 2 +- test/odt_md/pre-mie.md | 4 +- test/odt_md/project-overview.md | 27 +++++++------ test/odt_md/strong-headers.md | 8 ++-- 15 files changed, 114 insertions(+), 62 deletions(-) diff --git a/src/odt/OdtToMarkdown.ts b/src/odt/OdtToMarkdown.ts index e8593ae1..944bd150 100644 --- a/src/odt/OdtToMarkdown.ts +++ b/src/odt/OdtToMarkdown.ts @@ -232,12 +232,12 @@ export class OdtToMarkdown { const id = urlToFolderId(href); const hash = getUrlHash(link.href); if (id) { - href = 'gdoc:' + id; + href = 'gdoc:' + id + hash; } - this.addLink(href + hash); + this.addLink(href); - const block = this.chunks.createNode('A', { href: href + hash }); + const block = this.chunks.createNode('A', { href: href }); this.chunks.append(currentTagNode, block); currentTagNode = block; diff --git a/src/odt/markdownNodesUtils.ts b/src/odt/markdownNodesUtils.ts index 89ff83fc..5c0d385b 100644 --- a/src/odt/markdownNodesUtils.ts +++ b/src/odt/markdownNodesUtils.ts @@ -324,7 +324,7 @@ export async function walkRecursiveAsync(node: MarkdownNode, callback: (node: Ma const subCtx = await callback(node, ctx) || Object.assign({}, ctx); for (let nodeIdx = 0; nodeIdx < node.children.length; nodeIdx++) { const child = node.children[nodeIdx]; - const retVal = await walkRecursiveAsync(child, callback, { ...subCtx, nodeIdx }); + const retVal = await walkRecursiveAsync(child, callback, { ...subCtx, nodeIdx }, callbackEnd); if (retVal && 'nodeIdx' in retVal && typeof retVal.nodeIdx === 'number') { nodeIdx = retVal.nodeIdx; } diff --git a/src/odt/postprocess/postProcess.ts b/src/odt/postprocess/postProcess.ts index 6b6d97ea..defd6d68 100644 --- a/src/odt/postprocess/postProcess.ts +++ b/src/odt/postprocess/postProcess.ts @@ -39,12 +39,13 @@ export async function postProcess(chunks: MarkdownNodes, rewriteRules: RewriteRu convertCodeBlockParagraphs(chunks); convertMathMl(chunks); + trimParagraphs(chunks); + await rewriteHeaders(chunks); trimParagraphs(chunks); addEmptyLinesAfterParas(chunks); removeTdParas(chunks); // Requires: addEmptyLinesAfterParas mergeTexts(chunks); - await rewriteHeaders(chunks); mergeParagraphs(chunks); unwrapEmptyPre(chunks); diff --git a/src/odt/postprocess/rewriteHeaders.ts b/src/odt/postprocess/rewriteHeaders.ts index 0a6f66f7..c24ad8f5 100644 --- a/src/odt/postprocess/rewriteHeaders.ts +++ b/src/odt/postprocess/rewriteHeaders.ts @@ -1,16 +1,60 @@ import {walkRecursiveAsync} from '../markdownNodesUtils.ts'; -import {MarkdownNodes} from '../MarkdownNodes.ts'; +import {MarkdownNodes, MarkdownTextNode} from '../MarkdownNodes.ts'; export async function rewriteHeaders(markdownChunks: MarkdownNodes) { - await walkRecursiveAsync(markdownChunks.body, async (chunk) => { + let inPre = false; + await walkRecursiveAsync(markdownChunks.body, async (chunk, ctx: { nodeIdx: number }) => { + if (chunk.isTag && 'PRE' === chunk.tag) { + inPre = true; + } + + if (inPre) { + if (chunk.isTag) { + for (let j = chunk.children.length - 1; j >= 0; j--) { + const child = chunk.children[j]; + if (child.isTag && child.tag === 'BOOKMARK/') { + chunk.children.splice(j, 1); + break; + } + } + } + } + if (chunk.isTag && ['H1', 'H2', 'H3', 'H4'].includes(chunk.tag)) { - if (chunk.children.length > 1) { - const first = chunk.children[0]; - if (first.isTag && first.tag === 'BOOKMARK/') { - const toMove = chunk.children.splice(0, 1); + if (chunk.children.length === 1) { + const child = chunk.children[0]; + if (child.isTag && child.tag === 'BOOKMARK/') { + chunk.parent.children.splice(ctx.nodeIdx, 1, child); + return; + } + } + for (let j = 0; j < chunk.children.length - 1; j++) { + const child = chunk.children[j]; + if (child.isTag && child.tag === 'BOOKMARK/') { + const toMove = chunk.children.splice(j, 1); chunk.children.splice(chunk.children.length, 0, ...toMove); + break; } } } + }, {}, async (chunk) => { + if (chunk.isTag && 'PRE' === chunk.tag) { + inPre = false; + } + }); + + await walkRecursiveAsync(markdownChunks.body, async (chunk, ctx: { nodeIdx: number }) => { + if (chunk.isTag && 'BOOKMARK/' === chunk.tag) { + if (chunk.parent.children.length < 2) { + return; + } + const space: MarkdownTextNode = { + isTag: false, + text: ' ', + comment: 'rewriteHeaders.ts: space before anchor' + }; + chunk.parent.children.splice(ctx.nodeIdx, 0, space); + return { nodeIdx: ctx.nodeIdx + 1 }; + } }); } diff --git a/src/odt/postprocess/trimParagraphs.ts b/src/odt/postprocess/trimParagraphs.ts index 31621e04..0e88d0ec 100644 --- a/src/odt/postprocess/trimParagraphs.ts +++ b/src/odt/postprocess/trimParagraphs.ts @@ -26,7 +26,7 @@ export function trimParagraphs(markdownChunks: MarkdownNodes) { while (chunk.children.length > 0) { const firstChunk = chunk.children[0]; if (firstChunk.isTag === false) { - let origText = firstChunk.text; + const origText = firstChunk.text; firstChunk.text = firstChunk.text.replace(/^\s+/, ''); if (firstChunk.text === '') { diff --git a/src/utils/idParsers.ts b/src/utils/idParsers.ts index 1624ad01..a58018db 100644 --- a/src/utils/idParsers.ts +++ b/src/utils/idParsers.ts @@ -74,7 +74,7 @@ export function urlToFolderId(url: string): string | null { export function getUrlHash(url: string): string { const idx = url.indexOf('#'); - if (idx >= 0) { + if (idx >= 0 && idx < url.length - 1) { return url.substring(idx).replace('#heading=h.', '#_'); } return ''; diff --git a/test/odt_md/bullets.md b/test/odt_md/bullets.md index fa4a618a..7e3bc650 100644 --- a/test/odt_md/bullets.md +++ b/test/odt_md/bullets.md @@ -1,4 +1,4 @@ -## Bullet List +## Bullet List * Capability to print standard leave forms from the patient portal * Pre-loaded standard email templates @@ -6,7 +6,7 @@ * Quick View Absence Management Worklist * Leave Types Report -## Ordered List +## Ordered List 1. Capability to print standard leave forms from the patient portal 2. Pre-loaded standard email templates @@ -14,7 +14,7 @@ 4. Quick View Absence Management Worklist 5. Leave Types Report -## Mixed Lists +## Mixed Lists Item before list diff --git a/test/odt_md/confluence.md b/test/odt_md/confluence.md index 4b961fb1..d9a81fa6 100644 --- a/test/odt_md/confluence.md +++ b/test/odt_md/confluence.md @@ -1,14 +1,14 @@ -# Confluence to Google Docs Conversion Notes +# Confluence to Google Docs Conversion Notes -## Goal +## Goal Convert Confluence Documents in to Google Documents for the purpose of using WikiGDrive to publish them. -## Delivery +## Delivery A new github repo with a node.js script specific to this conversion. -## High level Process +## High level Process * Scan all of the documents in a Confluence Space * Make google documents in a shared drive (two passes will be required so links between documents can be known as content is added). @@ -18,7 +18,7 @@ A new github repo with a node.js script specific to this conversion. * Import content from Confluence Page into Google Documents * Heading should be headings * Paragraphs should be paragraphs - * Images (which are attachments in Confluence) should be embedded in google docs + * Images (which are attachments in Confluence) should be embedded in google docs * Macros can be wrapped in {{% curlies %}} and dumped as text * Example Block Macro: {{% macroname propertyname='value' propertyname='value' %}} @@ -30,13 +30,13 @@ A new github repo with a node.js script specific to this conversion. * Embedded Video should be converted to an image with a hyperlink * Formatting is not required to be converted. -## Proposed Instructions +## Proposed Instructions ``` confluence2google ``` -## Links and Possible Approaches +## Links and Possible Approaches 1. Use REST API 1. [Confluence Cloud REST API](https://developer.atlassian.com/cloud/confluence/rest/) @@ -50,7 +50,9 @@ confluence2google 3. Use HTML 1. [Confluence Export](https://confluence.atlassian.com/confcloud/import-a-confluence-space-724765531.html) that makes an HTML file -## Examples + + +## Examples Simple - [https://confluence.example.com/display/DOCS/Sample](https://confluence.example.com/display/DOCS/Sample) diff --git a/test/odt_md/example-document.md b/test/odt_md/example-document.md index 8e7a0d81..d2bd4180 100644 --- a/test/odt_md/example-document.md +++ b/test/odt_md/example-document.md @@ -7,13 +7,13 @@ * [Image](#image) * [Preformatted Text](#preformatted-text) -# Heading 1 +# Heading 1 -## Heading level 2 +## Heading level 2 Some normal text with hyperlinks to a [website](https://www.enterprisehealth.com/) and a link to a document on the [shared drive](gdoc:1H6vwfQXIexdg4ldfaoPUjhOZPnSkNn6h29WD6Fi-SBY) with multiple versions of [the link](gdoc:1H6vwfQXIexdg4ldfaoPUjhOZPnSkNn6h29WD6Fi-SBY) because people cut and paste. [Link to test page](gdoc:1iou0QW09pdUhaNtS1RfjJh12lxKAbbq91-SHGihXu_4). Link to [doc in another folder](gdoc:1G4xwfBdH5mvEQyGN16TD2vFUHP8aNgU7wPst-2QTZug). -### Heading level 3 - with a table +### Heading level 3 - with a table @@ -43,13 +43,13 @@ After subtable
-### Heading 3 - a diagram with links +### Heading 3 - a diagram with links [Diagram](gdoc:1Du-DYDST4liLykJl0fHSCvuQYIYhtOfwco-ntn38Dy8) [Diagram](gdoc:1Du-DYDST4liLykJl0fHSCvuQYIYhtOfwco-ntn38Dy8) -### Heading 3 - with a Table of contents +### Heading 3 - with a Table of contents * [Heading 1](#heading-1) * [Heading level 2](#heading-level-2) @@ -60,15 +60,15 @@ After subtable * [Image](#image) * [Preformatted Text](#preformatted-text) -# Other examples +# Other examples -## Image +## Image ![](1000000000000640000001CF60FB0243CA95EC14.jpg) ![](10000000000003F0000003F092F85671239C65F9.jpg) -## Preformatted Text +## Preformatted Text ``` This is monospaced text. This should line up | @@ -76,11 +76,11 @@ This is monospaced text. This should line up | ``` -## Code +## Code Code blocks are part of the Markdown spec, but syntax highlighting isn't. However, many renderers -- like Github's and *Markdown Here* -- support syntax highlighting. Which languages are supported and how those language names should be written will vary from renderer to renderer. *Markdown Here* supports highlighting for dozens of languages (and not-really-languages, like diffs and HTTP headers); to see the complete list, and how to write the language names, see the [highlight.js demo page](http://softwaremaniacs.org/media/soft/highlight/test.html). -### Typescript / Javascript +### Typescript / Javascript {{markdown}} ```javascript @@ -102,13 +102,13 @@ myArray.forEach(() => { }); // fat arrow syntax ``` {{/markdown}} -## Video +## Video From Youtube: [Google Drive, Docs, and Project Management with GSuite](https://www.youtube.com/watch?v=v6QAIWLCz8I&t=1743s) -## Horizontal Lines +## Horizontal Lines This is some text separated by a horizontal line @@ -116,7 +116,7 @@ ___ This is after the horizontal line. -## Lists +## Lists * Bullet 1 * Bullet 2 @@ -130,13 +130,13 @@ This is after the horizontal line. 2. Alpha 2 3. Alpha 3 -## Formatting +## Formatting Some **bold** **_boldanditalic_*** italic* text -## Equations +## Equations -### Using the actual equation object +### Using the actual equation object ```math E = m c^{2} @@ -146,13 +146,13 @@ E = m c^{2} e^{i \pi} - 1 = 0 ``` -### Text equivalent +### Text equivalent *E=mc**2* Inline $$E = m c^{2}$$ math -## Footnotes +## Footnotes 1Footnotes should display as a footnote, and should always display at the very end of the document (page)**?** This is some sample text with a footnote. diff --git a/test/odt_md/header-link.md b/test/odt_md/header-link.md index 2dda8f47..cc5752fe 100644 --- a/test/odt_md/header-link.md +++ b/test/odt_md/header-link.md @@ -4,6 +4,8 @@ See [Node setup on the system](#node-setup-on-the-system) for prereq. [Example Google Drive Shared Folder](gdoc:0AIkOKXbzWCtSUk9PVA) + + # Node setup on the system ## using OS diff --git a/test/odt_md/issue-432.md b/test/odt_md/issue-432.md index a1117e81..a112605e 100644 --- a/test/odt_md/issue-432.md +++ b/test/odt_md/issue-432.md @@ -1,4 +1,4 @@ -#### Test Methodology +#### Test Methodology MIE will report a count of messages for each supported message type: diff --git a/test/odt_md/issue-435-436.md b/test/odt_md/issue-435-436.md index 2488b631..44892fd8 100644 --- a/test/odt_md/issue-435-436.md +++ b/test/odt_md/issue-435-436.md @@ -1,4 +1,4 @@ -## Editing Existing Questions +## Editing Existing Questions Similar to adding a new question, users must have the proper permission to modify existing questions. diff --git a/test/odt_md/pre-mie.md b/test/odt_md/pre-mie.md index 5b72a4e0..ef21edd0 100644 --- a/test/odt_md/pre-mie.md +++ b/test/odt_md/pre-mie.md @@ -1,4 +1,4 @@ -## Request +## Request {{% pre language="html" theme="RDark" %}} ``` @@ -8,7 +8,7 @@ https://webchartnow.com/fhirr4sandbox/webchart.cgi/fhir/CarePlan/11 ``` {{% /pre %}} -## Response +## Response {{% pre language="json" theme="RDark" %}} ``` diff --git a/test/odt_md/project-overview.md b/test/odt_md/project-overview.md index 10736ba2..afa7c95b 100644 --- a/test/odt_md/project-overview.md +++ b/test/odt_md/project-overview.md @@ -12,7 +12,7 @@ * [Images](#images) * [FAQ](#faq) -# Wiki G Drive Project Overview +# Wiki G Drive Project Overview * [Wiki G Drive Project Overview](#wiki-g-drive-project-overview) * [Overview](#overview) @@ -28,7 +28,7 @@ * [Images](#images) * [FAQ](#faq) -## Overview +## Overview WikiGDrive is a node app that uses the [Google Drive API](https://developers.google.com/drive/api/v3/quickstart/nodejs) to transform Google Docs and Drawings into markdown. @@ -60,7 +60,7 @@ WikiGDrive GitHub -## Requirements +## Requirements The app must: @@ -84,7 +84,7 @@ Later phase: * Google sheets to CSV with MIE's datavis * Markdown -> Google Docs converter -## Instructions (proposed) +## Instructions (proposed) npm install wikigdrive @@ -106,7 +106,7 @@ Options: wikigdrive keeps a local JSON config file in the dest directory with state from prior runs. The config contains a map of URL driveIds to the local filenames along with metadata about each file. -## Renames and Redirecting +## Renames and Redirecting When a Document is renamed or moved in the shared drive the driveId says the same, but its place in the filesystem changes. For example a document named "Carbon" would be created as Carbon.md. Sometime later its renamed to "Carbon Fiber" then a new file "Carbon Fiber.md" would be made with the content and the old "Carbon.md" is changed to: @@ -141,7 +141,7 @@ Then sometime later, "Example 1" is renamed to "Sample 1" the folder layout shou * Example-1.md -> /Container/Sample-1.md * Example-2.md -> /Container/Example-2.md -## Collisions with Filenames +## Collisions with Filenames Google Drive allows filenames with the same name to be created on shared drives. When transforming them into the local filesystem, each file will be renamed to a new file and a disambiguation page will be placed in their place. Eg: @@ -161,11 +161,13 @@ The contents of Carbon.md would show each of the conflicting references: * [Carbon](Carbon-2.md) -## Table of Contents and Index + + +## Table of Contents and Index In the root of the local filesystem two files will be created: the toc.md and index.md -### Table of Contents +### Table of Contents The table of contents is a layout of the documents and their position in the drive as an unordered list. It should not contain redirected files, images, etc. @@ -173,7 +175,7 @@ The table of contents is a layout of the documents and their position in the dri The index is a listing of all of the defined terms and their references in the documents. The processing may be passed to another tool to construct the index. Examples: [kramdown](https://meta.stackexchange.com/questions/72395/is-it-possible-to-have-definition-lists-in-markdown), [Asciidoctor](https://asciidoctor.org/docs/user-manual/) -## Markdown Cleanup +## Markdown Cleanup * Bold headings: ([issue](https://github.com/mieweb/wikiGDrive/issues/17)) Remove the ** bold markdown from all headings. ![](10000201000001A5000000492C856905A808045C.png) @@ -181,14 +183,15 @@ The index is a listing of all of the defined terms and their references in the d ![](10000201000005480000004BB83F3F8B5F0C77BD.png) * Italics/bold in an unordered list: ([issue](https://github.com/mieweb/wikiGDrive/issues/16)) Italics are not being rendered if in a list item. We may need to find these and replace the */** with em/strong tags. Example is rendered in browser next to [Google Doc](gdoc:108WScoxxGKKKOsGWF7UNZ4rLRanGXu6BPdJ-axjVn5s). ![](1000020100000243000000F28AB7617254FDBB3A.png) - -## Images + + +## Images Two kinds of images exist within Google Docs: 1) Embedded images stored within the document and 2) images that are referenced to another "Drawing" on the google drive. WikiGDrive processes images by placing them in a folder named with a similar name to the page. (eg: index.md would result in a folder index.images with each embedded image in that folder). If you make a drawing somewhere in the google drive folder and link it in the google document (WITH A HYPERLINK b/c Google does not expose the internal link via the api) then WikiGDrive will process the drawing as a SVG and place a proper reference to the SVG in the markdown. -## FAQ +## FAQ * What is the purpose of this tool? * To enable collaborative editing of documentation and the ability to publish that documentation as well as linking it to revision control system branches (like in git) diff --git a/test/odt_md/strong-headers.md b/test/odt_md/strong-headers.md index b21393a9..b01843ec 100644 --- a/test/odt_md/strong-headers.md +++ b/test/odt_md/strong-headers.md @@ -1,4 +1,4 @@ -## Data Migration Workflow Considerations +## Data Migration Workflow Considerations As we may recall, the Health Surveillance module allows users to easily track and manage overall health for risk groups and patient populations. Following that is information on how to utilize the import/export tools available with every {{% system-name %}} system. @@ -9,7 +9,7 @@ Health Surveillance (HS) Data is typically broken down into 4 parts during the d 1. Active HS Memberships and Next Due Dates 2. Historical HS Memberships -#### Active HS Memberships and Next Due Dates +#### Active HS Memberships and Next Due Dates Nearly every {{% sys-name %}} data migration involves the migration of active HS memberships and Next Due Dates. Membership inclusions and exclusions may be explicit or implicit depending on the configuration of each panel, and those decisions will all weigh into the scoping of the data migration. @@ -20,11 +20,11 @@ Some clients require the migration of historical, or non-active HS memberships. 1. Discrete data migration of Historical HS Memberships involves migrating memberships with a Begin and End Date for each employee's expired panel. Discrete migrations such as these require mapping each legacy panel membership to {{% sys-name %}} panels, which will then allow for the reporting of historical panel memberships and dates, per employee. 2. Non-Discrete summary documents of historical HS memberships provide a single document showing the legacy name of the panel for each chart with HS memberships, along with the start- and end-dates where that data is available. These documents are significantly less effort than discrete data migrations of historical HS memberships, and allow clinicians to reference the historical entry and exit data of an employee's memberships. -#### Open Orders +#### Open Orders In some cases, open or pending orders are required for migration for employees with overdue but active panel memberships. This use case is discussed further in the section on [How to determine the Next Due Date on a HS Panel](#how-to-determine-the-next-due-date-on-a-hs-panel). -#### Historical Orders +#### Historical Orders In some cases, migration of completed orders are required to show that tests or tasks were completed on a particular date. Like any other data migration, discrete migration of historical orders involves more mapping and more effort than creating a summary document of historical orders. The following use cases are most common where the migration of historical orders are needed: