Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/hashlinks #477

Merged
merged 1 commit into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/LinkTranslator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function convertExtension(localPath: string, mode?: LinkMode) {
return dirName + parts.join('.');
}

export function convertToRelativeMarkDownPath(localPath, basePath) {
export function convertToRelativeMarkDownPath(localPath: string, basePath: string) {
if (localPath.startsWith('https://')) return localPath;
if (localPath.startsWith('http://')) return localPath;
if (basePath === localPath) return '.';
Expand All @@ -51,7 +51,7 @@ export function convertToRelativeMarkDownPath(localPath, basePath) {
})));
}

export function convertToRelativeSvgPath(localPath, basePath) {
export function convertToRelativeSvgPath(localPath: string, basePath: string) {
if (localPath.startsWith('https://')) return localPath;
if (localPath.startsWith('http://')) return localPath;
if (basePath === localPath) return '.';
Expand Down
2 changes: 1 addition & 1 deletion src/containers/server/ServerContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {GoogleTreeProcessor} from '../google_folder/GoogleTreeProcessor.ts';
import {initStaticDistPages} from './static.ts';
import {initUiServer} from './vuejs.ts';
import {initErrorHandler} from './error.ts';
import {WebHookController} from './routes/WebHookController.js';
import {WebHookController} from './routes/WebHookController.ts';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
Expand Down
2 changes: 1 addition & 1 deletion src/containers/transform/TaskGoogleMarkdownTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {SvgTransform} from '../../SvgTransform.ts';
import {generateDocumentFrontMatter} from './frontmatters/generateDocumentFrontMatter.ts';
import {generateConflictMarkdown} from './frontmatters/generateConflictMarkdown.ts';
import {googleMimeToExt} from './TaskLocalFileTransform.ts';
import {getUrlHash, urlToFolderId} from '../../utils/idParsers.js';
import {getUrlHash, urlToFolderId} from '../../utils/idParsers.ts';

export class TaskGoogleMarkdownTransform extends QueueTask {
constructor(protected logger: winston.Logger,
Expand Down
10 changes: 9 additions & 1 deletion src/containers/transform/TaskLocalFileTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export class TaskLocalFileTransform extends QueueTask {
private destinationDirectory: FileContentService,
private localFile: LocalFile,
private localLinks: LocalLinks,
private userConfig: UserConfig
private userConfig: UserConfig,
private globalHeadersMap: {[key: string]: string},
) {
super(logger);
this.retries = 0;
Expand Down Expand Up @@ -128,6 +129,7 @@ export class TaskLocalFileTransform extends QueueTask {
async generateDocument(localFile: MdFile) {
let frontMatter;
let markdown;
let headersMap = {};
let links = [];
let errors = [];

Expand Down Expand Up @@ -163,6 +165,7 @@ export class TaskLocalFileTransform extends QueueTask {
} else {
converter.setPicturesDir('../' + this.realFileName.replace(/.md$/, '.assets/'), picturesDirAbsolute);
}
headersMap = converter.getHeadersMap();
markdown = await converter.convert();
links = Array.from(converter.links);
frontMatter = generateDocumentFrontMatter(localFile, links, this.userConfig.fm_without_version);
Expand All @@ -174,6 +177,7 @@ export class TaskLocalFileTransform extends QueueTask {
frontMatter: string;
markdown: string;
errors: Array<string>;
headersMap: {[key: string]: string};
}

const workerResult: WorkerResult = <WorkerResult>await this.jobManagerContainer.scheduleWorker('OdtToMarkdown', {
Expand All @@ -190,6 +194,7 @@ export class TaskLocalFileTransform extends QueueTask {
frontMatter = workerResult.frontMatter;
markdown = workerResult.markdown;
errors = workerResult.errors;
headersMap = workerResult.headersMap;
this.warnings = errors.length;
}

Expand All @@ -202,6 +207,9 @@ export class TaskLocalFileTransform extends QueueTask {

await this.destinationDirectory.writeFile(this.realFileName, frontMatter + markdown);
this.localLinks.append(localFile.id, localFile.fileName, links);
for (const k in headersMap) {
this.globalHeadersMap['gdoc:' + localFile.id + k] = 'gdoc:' + localFile.id + headersMap[k];
}
}

async generate(localFile: LocalFile): Promise<void> {
Expand Down
21 changes: 14 additions & 7 deletions src/containers/transform/TransformContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {GoogleFilesScanner} from './GoogleFilesScanner.ts';
import {convertToRelativeMarkDownPath, convertToRelativeSvgPath} from '../../LinkTranslator.ts';
import {LocalFilesGenerator} from './LocalFilesGenerator.ts';
import {QueueTransformer} from './QueueTransformer.ts';
import {NavigationHierarchy} from './generateNavigationHierarchy.ts';
import {ConflictFile, LocalFile, RedirFile} from '../../model/LocalFile.ts';
import {TaskLocalFileTransform} from './TaskLocalFileTransform.ts';
import {MimeTypes} from '../../model/GoogleFile.ts';
Expand Down Expand Up @@ -200,7 +199,6 @@ export class TransformLog extends Transport {
export class TransformContainer extends Container {
private logger: winston.Logger;
private generatedFileService: FileContentService;
private hierarchy: NavigationHierarchy = {};
private localLog: LocalLog;
private localLinks: LocalLinks;
private filterFilesIds: FileId[];
Expand All @@ -210,6 +208,7 @@ export class TransformContainer extends Container {
private transformLog: TransformLog;
private isFailed = false;
private useGoogleMarkdowns = false;
private globalHeadersMap: {[key: string]: string} = {};

constructor(public readonly params: ContainerConfig, public readonly paramsArr: ContainerConfigArr = {}) {
super(params, paramsArr);
Expand Down Expand Up @@ -299,7 +298,8 @@ export class TransformContainer extends Container {
destinationDirectory,
localFile,
this.localLinks,
this.userConfigService.config
this.userConfigService.config,
this.globalHeadersMap
);
queueTransformer.addTask(task);
} else {
Expand Down Expand Up @@ -443,15 +443,22 @@ export class TransformContainer extends Container {

if (fileName.endsWith('.md') || fileName.endsWith('.svg')) {
const content = await destinationDirectory.readFile(fileName);
const newContent = content.replace(/(gdoc:[A-Z0-9_-]+)/ig, (str: string) => {
const fileId = str.substring('gdoc:'.length).replace(/#.*/, '');
const hash = getUrlHash(str);
const newContent = content.replace(/(gdoc:[A-Z0-9_-]+)(#[^'")\s]*)?/ig, (str: string) => {
let fileId = str.substring('gdoc:'.length).replace(/#.*/, '');
let hash = getUrlHash(str) || '';
if (hash && this.globalHeadersMap[str]) {
const idx = this.globalHeadersMap[str].indexOf('#');
if (idx >= 0) {
fileId = this.globalHeadersMap[str].substring('gdoc:'.length, idx);
hash = this.globalHeadersMap[str].substring(idx);
}
}
const lastLog = this.localLog.findLastFile(fileId);
if (lastLog && lastLog.event !== 'removed') {
if (fileName.endsWith('.svg')) {
return convertToRelativeSvgPath(lastLog.filePath, destinationDirectory.getVirtualPath() + fileName);
} else {
return convertToRelativeMarkDownPath(lastLog.filePath, destinationDirectory.getVirtualPath() + fileName);
return convertToRelativeMarkDownPath(lastLog.filePath, destinationDirectory.getVirtualPath() + fileName) + hash;
}
} else {
return 'https://drive.google.com/open?id=' + fileId + hash.replace('#_', '#heading=h.');
Expand Down
10 changes: 8 additions & 2 deletions src/odt/OdtToMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class OdtToMarkdown {
private picturesDir = '';
private picturesDirAbsolute = '';
private rewriteRules: RewriteRule[] = [];
private headersMap: { [p: string]: string } = {};

constructor(private document: DocumentContent, private documentStyles: DocumentStyles, private fileNameMap: StringToStringMap = {}, private xmlMap: StringToStringMap = {}) {
}
Expand Down Expand Up @@ -131,7 +132,8 @@ export class OdtToMarkdown {
// text = this.processMacros(text);
// text = this.fixBlockMacros(text);

await postProcess(this.chunks, this.rewriteRules);
const { headersMap } = await postProcess(this.chunks, this.rewriteRules);
this.headersMap = headersMap;

const markdown = this.chunks.toString();
return this.trimBreaks(markdown);
Expand Down Expand Up @@ -223,7 +225,7 @@ export class OdtToMarkdown {

addLink(href: string) {
if (href && !href.startsWith('#') && href.indexOf(':') > -1) {
this.links.add(href);
this.links.add(href.replace(/#.*$/, ''));
}
}

Expand Down Expand Up @@ -701,4 +703,8 @@ export class OdtToMarkdown {
this.errors.push(error);
}

getHeadersMap() {
return this.headersMap;
}

}
4 changes: 3 additions & 1 deletion src/odt/executeOdtToMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ export async function executeOdtToMarkdown(workerData) {
fs.writeFileSync(path.join(workerData.destinationPath, workerData.realFileName.replace(/.md$/, '.debug.xml')), markdown);
}

return { links, frontMatter, markdown, errors };
const headersMap = converter.getHeadersMap();

return { links, frontMatter, markdown, errors, headersMap };
}
4 changes: 3 additions & 1 deletion src/odt/postprocess/postProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function postProcess(chunks: MarkdownNodes, rewriteRules: RewriteRu
convertMathMl(chunks);

trimParagraphs(chunks);
await rewriteHeaders(chunks);
const { headersMap} = await rewriteHeaders(chunks);
trimParagraphs(chunks);
addEmptyLinesAfterParas(chunks);
removeTdParas(chunks); // Requires: addEmptyLinesAfterParas
Expand All @@ -67,4 +67,6 @@ export async function postProcess(chunks: MarkdownNodes, rewriteRules: RewriteRu
if (process.env.DEBUG_COLORS) {
dump(chunks.body);
}

return { headersMap };
}
28 changes: 25 additions & 3 deletions src/odt/postprocess/rewriteHeaders.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {walkRecursiveAsync} from '../markdownNodesUtils.ts';
import slugify from 'slugify';
import {extractText, walkRecursiveAsync, walkRecursiveSync} from '../markdownNodesUtils.ts';
import {MarkdownNodes, MarkdownTextNode} from '../MarkdownNodes.ts';

export async function rewriteHeaders(markdownChunks: MarkdownNodes) {
export async function rewriteHeaders(markdownChunks: MarkdownNodes): Promise<{ headersMap: {[key: string]: string} }> {
const headersMap = {};

let inPre = false;
await walkRecursiveAsync(markdownChunks.body, async (chunk, ctx: { nodeIdx: number }) => {
if (chunk.isTag && 'PRE' === chunk.tag) {
Expand All @@ -21,6 +24,9 @@ export async function rewriteHeaders(markdownChunks: MarkdownNodes) {
}

if (chunk.isTag && ['H1', 'H2', 'H3', 'H4'].includes(chunk.tag)) {
const innerTxt = extractText(chunk);
const slug = slugify(innerTxt.trim(), { replacement: '-', lower: true, remove: /[#*+~.,^()'"!:@]/g });

if (chunk.children.length === 1) {
const child = chunk.children[0];
if (child.isTag && child.tag === 'BOOKMARK/') {
Expand All @@ -32,7 +38,11 @@ export async function rewriteHeaders(markdownChunks: MarkdownNodes) {
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);
if (slug && !headersMap['#' + child.payload.id]) {
headersMap['#' + child.payload.id] = '#' + slug;
} else {
chunk.children.splice(chunk.children.length, 0, ...toMove);
}
break;
}
}
Expand All @@ -57,4 +67,16 @@ export async function rewriteHeaders(markdownChunks: MarkdownNodes) {
return { nodeIdx: ctx.nodeIdx + 1 };
}
});

if (Object.keys(headersMap).length > 0) {
walkRecursiveSync(markdownChunks.body, (chunk) => {
if (chunk.isTag === true && chunk.payload?.href) {
if (headersMap[chunk.payload.href]) {
chunk.payload.href = headersMap[chunk.payload.href];
}
}
});
}

return { headersMap };
}
2 changes: 0 additions & 2 deletions test/git/RebaseTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,6 @@ describe('RebaseTest', function () {
{
const history = await scannerLocal.history('');

console.log('historyhistory', history);

assert.equal(2, history.length);
assert.equal('Change on second repo', history[0].message);

Expand Down
6 changes: 3 additions & 3 deletions test/odt_md/bullets.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
## Bullet List <a id="_80qew9aprjq8"></a>
## Bullet List

* Capability to print standard leave forms from the patient portal
* Pre-loaded standard email templates
* Absence Management encounter
* Quick View Absence Management Worklist
* Leave Types Report

## Ordered List <a id="_k2lx86ardtkr"></a>
## Ordered List

1. Capability to print standard leave forms from the patient portal
2. Pre-loaded standard email templates
3. Absence Management encounter
4. Quick View Absence Management Worklist
5. Leave Types Report

## Mixed Lists <a id="_xnxyy4ptrcvu"></a>
## Mixed Lists

Item before list

Expand Down
14 changes: 7 additions & 7 deletions test/odt_md/confluence.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Confluence to Google Docs Conversion Notes <a id="_77510dqpcwl"></a>
# Confluence to Google Docs Conversion Notes

## Goal <a id="_10c0ntqm6mev"></a>
## Goal

Convert Confluence Documents in to Google Documents for the purpose of using WikiGDrive to publish them.

## Delivery <a id="_i96xic41327t"></a>
## Delivery

A new github repo with a node.js script specific to this conversion.

## High level Process <a id="_wrw8sf3g3pc3"></a>
## 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).
Expand All @@ -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 <a id="_m98292szff3y"></a>
## Proposed Instructions

```
confluence2google <path to space> <path to google shared drive>
```

## Links and Possible Approaches <a id="_sdx7522zhby"></a>
## Links and Possible Approaches

1. Use REST API
1. [Confluence Cloud REST API](https://developer.atlassian.com/cloud/confluence/rest/)
Expand All @@ -52,7 +52,7 @@ confluence2google <path to space> <path to google shared drive>

<a id="ggsym7lvzx37"></a>

## Examples <a id="_rsmqmchgeq17"></a>
## Examples

Simple - [https://confluence.example.com/display/DOCS/Sample](https://confluence.example.com/display/DOCS/Sample)

Expand Down
Loading