diff --git a/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts b/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts index f2c873a7c5..e1eb166416 100644 --- a/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts +++ b/src/sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component.ts @@ -24,6 +24,7 @@ import { URI } from 'vs/base/common/uri'; import { escape } from 'vs/base/common/strings'; import { IImageCalloutDialogOptions, ImageCalloutDialog } from 'sql/workbench/contrib/notebook/browser/calloutDialog/imageCalloutDialog'; import { TextCellEditModes } from 'sql/workbench/services/notebook/common/contracts'; +import { NotebookLinkHandler } from 'sql/workbench/contrib/notebook/browser/notebookLinkHandler'; export const MARKDOWN_TOOLBAR_SELECTOR: string = 'markdown-toolbar-component'; const linksRegex = /\[(?.+)\]\((?[^ ]+)(?: "(?.+)")?\)/; @@ -239,19 +240,11 @@ export class MarkdownToolbarComponent extends AngularDisposable { if (this.cellModel.currentMode !== CellEditModes.WYSIWYG) { needsTransform = false; } else { - let linkUrl = linkCalloutResult.insertUnescapedLinkUrl; - const isAnchorLink = linkUrl.startsWith('#'); - if (!isAnchorLink) { - const isFile = URI.parse(linkUrl).scheme === 'file'; - if (isFile && !path.isAbsolute(linkUrl)) { - const notebookDirName = path.dirname(this.cellModel?.notebookModel?.notebookUri.fsPath); - const relativePath = (linkUrl).replace(/\\/g, path.posix.sep); - linkUrl = path.resolve(notebookDirName, relativePath); - } - } + let notebookLink = new NotebookLinkHandler(this.cellModel?.notebookModel?.notebookUri, linkCalloutResult.insertUnescapedLinkUrl, this._configurationService); + let linkUrl = notebookLink.getLinkUrl(); // Otherwise, re-focus on the output element, and insert the link directly. this.output?.nativeElement?.focus(); - document.execCommand('insertHTML', false, `<a href="${escape(linkUrl)}">${escape(linkCalloutResult?.insertUnescapedLinkLabel)}</a>`); + document.execCommand('insertHTML', false, `<a href="${escape(linkUrl)}" is-absolute=${notebookLink.isAbsolutePath}>${escape(linkCalloutResult?.insertUnescapedLinkLabel)}</a>`); return; } } else if (type === MarkdownButtonType.IMAGE_PREVIEW) { @@ -356,12 +349,8 @@ export class MarkdownToolbarComponent extends AngularDisposable { return ''; } const parentNode = anchorNode.parentNode as HTMLAnchorElement; - if (parentNode?.protocol === 'file:') { - // Pathname starts with / per https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/pathname so trim it off - return parentNode.pathname?.slice(1) || ''; - } else { - return parentNode.href || ''; - } + const linkHandler = new NotebookLinkHandler(this.cellModel?.notebookModel?.notebookUri, parentNode, this._configurationService); + return linkHandler.getLinkUrl(); } else { const editorControl = this.getCellEditorControl(); const selection = editorControl?.getSelection(); diff --git a/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts b/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts index 5dece342c6..b09c675779 100644 --- a/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts +++ b/src/sql/workbench/contrib/notebook/browser/cellViews/textCell.component.ts @@ -177,7 +177,7 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges { this.updateTheme(this.themeService.getColorTheme()); this.setFocusAndScroll(); this.cellModel.isEditMode = false; - this._htmlMarkdownConverter = new HTMLMarkdownConverter(this.notebookUri); + this._htmlMarkdownConverter = this._instantiationService.createInstance(HTMLMarkdownConverter, this.notebookUri); this._register(this.cellModel.onOutputsChanged(e => { this.updatePreview(); })); diff --git a/src/sql/workbench/contrib/notebook/browser/htmlMarkdownConverter.ts b/src/sql/workbench/contrib/notebook/browser/htmlMarkdownConverter.ts index 07b9b4c138..b2f8632554 100644 --- a/src/sql/workbench/contrib/notebook/browser/htmlMarkdownConverter.ts +++ b/src/sql/workbench/contrib/notebook/browser/htmlMarkdownConverter.ts @@ -7,7 +7,8 @@ import TurndownService = require('turndown'); import { URI } from 'vs/base/common/uri'; import * as path from 'vs/base/common/path'; import * as turndownPluginGfm from 'sql/workbench/contrib/notebook/browser/turndownPluginGfm'; -import { replaceInvalidLinkPath } from 'sql/workbench/contrib/notebook/common/utils'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { findPathRelativeToContent, NotebookLinkHandler } from 'sql/workbench/contrib/notebook/browser/notebookLinkHandler'; // These replacements apply only to text. Here's how it's handled from Turndown: // if (node.nodeType === 3) { @@ -30,10 +31,11 @@ const markdownReplacements = [ [/</g, '\\<'], // Added to ensure sample text like <hello> is escaped [/>/g, '\\>'], // Added to ensure sample text like <hello> is escaped ]; + export class HTMLMarkdownConverter { private turndownService: TurndownService; - constructor(private notebookUri: URI) { + constructor(private notebookUri: URI, @IConfigurationService private configurationService: IConfigurationService,) { this.turndownService = new TurndownService({ 'emDelimiter': '_', 'bulletListMarker': '-', 'headingStyle': 'atx', blankReplacement: blankReplacement }); this.setTurndownOptions(); } @@ -132,27 +134,8 @@ export class HTMLMarkdownConverter { this.turndownService.addRule('a', { filter: 'a', replacement: (content, node) => { - let href = node.href; - let notebookLink: URI | undefined; - const isAnchorLinkInFile = (node.attributes.href?.nodeValue.startsWith('#') || href.includes('#')) && href.startsWith('file://'); - if (isAnchorLinkInFile) { - notebookLink = getUriAnchorLink(node, this.notebookUri); - } else { - //On Windows, if notebook is not trusted then the href attr is removed for all non-web URL links - // href contains either a hyperlink or a URI-encoded absolute path. (See resolveUrls method in notebookMarkdown.ts) - notebookLink = href ? URI.parse(href) : URI.file(node.title); - } - const notebookFolder = this.notebookUri ? path.join(path.dirname(this.notebookUri.fsPath), path.sep) : ''; - if (notebookLink.fsPath !== this.notebookUri.fsPath) { - let relativePath = findPathRelativeToContent(notebookFolder, notebookLink); - if (relativePath) { - return `[${node.innerText}](${relativePath})`; - } - } else if (notebookLink?.fragment) { - // if the anchor link is to a section in the same notebook then just add the fragment - return `[${content}](${notebookLink.fragment})`; - } - + const linkHandler = new NotebookLinkHandler(this.notebookUri, node, this.configurationService); + const href = linkHandler.getLinkUrl(); return `[${content}](${href})`; } }); @@ -304,25 +287,6 @@ function isInsideTable(node): boolean { return node.parentNode?.nodeName === 'TH' || node.parentNode?.nodeName === 'TD'; } -export function findPathRelativeToContent(notebookFolder: string, contentPath: URI | undefined): string { - if (notebookFolder) { - if (contentPath?.scheme === 'file') { - let relativePath = contentPath.fragment ? path.relative(notebookFolder, contentPath.fsPath).concat('#', contentPath.fragment) : path.relative(notebookFolder, contentPath.fsPath); - //if path contains whitespaces then it's not identified as a link - relativePath = relativePath.replace(/\s/g, '%20'); - // if relativePath contains improper directory format due to marked js parsing returning an invalid path (ex. ....\) then we need to replace it to ensure the directories are formatted properly (ex. ..\..\) - relativePath = replaceInvalidLinkPath(relativePath); - if (relativePath.startsWith(path.join('..', path.sep)) || relativePath.startsWith(path.join('.', path.sep))) { - return relativePath; - } else { - // if the relative path does not contain ./ at the beginning, we need to add it so it's recognized as a link - return `.${path.join(path.sep, relativePath)}`; - } - } - } - return ''; -} - export function addHighlightIfYellowBgExists(node, content: string): string { if (node?.style?.backgroundColor === 'yellow') { return '<mark>' + content + '</mark>'; @@ -330,14 +294,3 @@ export function addHighlightIfYellowBgExists(node, content: string): string { return content; } -export function getUriAnchorLink(node, notebookUri: URI): URI { - const sectionLinkToAnotherFile = node.href.includes('#') && !node.attributes.href?.nodeValue.startsWith('#'); - if (sectionLinkToAnotherFile) { - let absolutePath = !path.isAbsolute(node.attributes.href?.nodeValue) ? path.resolve(path.dirname(notebookUri.fsPath), node.attributes.href?.nodeValue) : node.attributes.href?.nodeValue; - // if section link is different from the current notebook - return URI.file(absolutePath); - } else { - // else build an uri using the current notebookUri - return URI.from({ scheme: 'file', path: notebookUri.path, fragment: node.attributes.href?.nodeValue }); - } -} diff --git a/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts index c757ebc9c6..6d2b86e2c5 100644 --- a/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -335,6 +335,11 @@ configurationRegistry.registerConfiguration({ 'default': 200, 'minimum': 10, 'description': localize('notebook.maxRichTextUndoHistory', "The maximum number of changes stored in the undo history for the notebook Rich Text editor.") + }, + 'notebook.useAbsoluteFilePaths': { + 'type': 'boolean', + 'default': false, + 'description': localize('notebook.useAbsoluteFilePaths', "Use absolute file paths when linking to other notebooks.") } } }); diff --git a/src/sql/workbench/contrib/notebook/browser/notebookLinkHandler.ts b/src/sql/workbench/contrib/notebook/browser/notebookLinkHandler.ts new file mode 100644 index 0000000000..3e23cede9c --- /dev/null +++ b/src/sql/workbench/contrib/notebook/browser/notebookLinkHandler.ts @@ -0,0 +1,145 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import * as path from 'vs/base/common/path'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { replaceInvalidLinkPath } from 'sql/workbench/contrib/notebook/common/utils'; +import { isWindows } from 'vs/base/common/platform'; + +const keepAbsolutePathConfigName = 'notebook.keepAbsolutePath'; + +export class NotebookLinkHandler { + private _notebookUriLink: URI; + private _href: string; + private _notebookDirectory: string; + private _isAnchorLink: boolean; + private _isFile: boolean; + public readonly isAbsolutePath: boolean; + + constructor( + private _notebookURI: URI, + private _link: string | HTMLAnchorElement, + @IConfigurationService private _configurationService: IConfigurationService, + ) { + if (typeof this._link === 'string') { + this._notebookUriLink = URI.parse(this._link); + this._isFile = this._notebookUriLink.scheme === 'file'; + this.isAbsolutePath = path.isAbsolute(this._link); + this._isAnchorLink = this._link.includes('#') && this._isFile; + } else { + // HTMLAnchorElement + // windows files need to use the link.href instead as it contains the file:// prefix + // which enables us to get the proper relative path + if (isWindows) { + this._href = this._link.href; + } else { + this._href = this._link.attributes['href']?.nodeValue; + } + this._notebookUriLink = this._href ? URI.parse(this._href) : undefined; + this._isFile = this._link.protocol === 'file:'; + this._isAnchorLink = this._notebookUriLink?.fragment ? true : false; + this.isAbsolutePath = this._link.attributes['is-absolute']?.nodeValue === 'true' ? true : false; + } + this._notebookDirectory = this._notebookURI ? path.dirname(this._notebookURI.fsPath) : ''; + } + + /** + * Function to get the link for LinkCalloutDialog or htmlMarkdownConverter + * When a user inserts a new link via the LinkCalloutDialog it will go through the string case to + * get the absolute path of the file and then will be converted to anchor element that will be called again + * to the object case in which we will find the relative path of the file unless the user has the + * keep absolute setting enabled then we don't convert absolute paths to relative paths + * @returns the file link or web link + */ + public getLinkUrl(): string { + // cases where we only have the href link + if (typeof this._link === 'string') { + // Does not convert absolute path to relative path + if (this._isFile && this.isAbsolutePath && this._configurationService.getValue(keepAbsolutePathConfigName) === true) { + return this._link; + } + // sets the string to absolute path to be used to resolve + if (this._isFile && !this.isAbsolutePath && !this._isAnchorLink) { + const relativePath = (this._link).replace(/\\/g, path.posix.sep); + const linkUrl = path.resolve(this._notebookDirectory, relativePath); + return linkUrl; + } + /** + * We return the absolute path for the link so that it will get used in the as the href for the anchor HTML element + * (in linkCalloutDialog document.execCommand('insertHTML') and therefore will call getLinkURL() with HTMLAnchorElement to then get the relative path + */ + return this._link; + } else { + // cases where we pass the HTMLAnchorElement + if (this._notebookUriLink && this._isFile) { + let targetUri: URI; + // Does not convert absolute path to relative path if keep Absolute Path setting is enabled + if (this.isAbsolutePath && this._configurationService.getValue(keepAbsolutePathConfigName) === true) { + return escape(this._href); + } else { + if (this._isAnchorLink) { + targetUri = this.getUriAnchorLink(this._link, this._notebookURI); + } else { + //On Windows, if notebook is not trusted then the href attr is removed for all non-web URL links + // href contains either a hyperlink or a URI-encoded absolute path. (See resolveUrls method in notebookMarkdown.ts) + targetUri = this._link ? this._notebookUriLink : URI.file(this._link.title); + } + // returns relative path of target notebook to the current notebook directory + if (this._notebookUriLink.fsPath !== this._notebookURI.fsPath && !targetUri?.fragment) { + return findPathRelativeToContent(this._notebookDirectory, targetUri); + } else { + // if the anchor link is to a section in the same notebook then just add the fragment + return targetUri.fragment; + } + } + } + // Web links + return this._href || ''; + } + } + + /** + * Creates a URI for for a link with a anchor (#) + * @param node is the HTMLAnchorElement of the target notebook + * @param notebookUri is current notebook URI + * @returns URI of the link with the anchor + */ + public getUriAnchorLink(node, notebookUri: URI): URI { + const sectionLinkToAnotherFile = node.href.includes('#') && !node.attributes.href?.nodeValue.startsWith('#'); + if (sectionLinkToAnotherFile) { + let absolutePath = !path.isAbsolute(node.attributes.href?.nodeValue) ? path.resolve(path.dirname(notebookUri.fsPath), node.attributes.href?.nodeValue) : node.attributes.href?.nodeValue; + // if section link is different from the current notebook + return URI.file(absolutePath); + } else { + // else build an uri using the current notebookUri + return URI.from({ scheme: 'file', path: notebookUri.path, fragment: node.attributes.href?.nodeValue }); + } + } + +} + +/** + * Finds the Relative Path from current notebook folder to target (linked) notebook + * @param notebookFolder is the current notebook directory + * @param contentPath is the URI path to the notebook we are linking to + * @returns relative path from the current notebook to the target notebook + */ +export function findPathRelativeToContent(notebookFolder: string, contentPath: URI | undefined): string { + if (contentPath?.scheme === 'file') { + let relativePath = contentPath.fragment ? path.relative(notebookFolder, contentPath.fsPath).concat('#', contentPath.fragment) : path.relative(notebookFolder, contentPath.fsPath); + //if path contains whitespaces then it's not identified as a link + relativePath = relativePath.replace(/\s/g, '%20'); + // if relativePath contains improper directory format due to marked js parsing returning an invalid path (ex. ....\) then we need to replace it to ensure the directories are formatted properly (ex. ..\..\) + relativePath = replaceInvalidLinkPath(relativePath); + if (relativePath.startsWith(path.join('..', path.sep)) || relativePath.startsWith(path.join('.', path.sep))) { + return relativePath; + } else { + // if the relative path does not contain ./ at the beginning, we need to add it so it's recognized as a link + return `.${path.join(path.sep, relativePath)}`; + } + } + return ''; +} diff --git a/src/sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown.ts b/src/sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown.ts index 48db8b5756..d0174c1214 100644 --- a/src/sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown.ts +++ b/src/sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown.ts @@ -108,6 +108,8 @@ export class NotebookMarkdownRenderer { return '<img ' + attributes.join(' ') + '>'; }; renderer.link = (href: string, title: string, text: string): string => { + // check for isAbsolute prior to escaping and replacement + let hrefAbsolute: boolean = path.isAbsolute(href); href = this.cleanUrl(!markdown.isTrusted, notebookFolder, href); if (href === null) { return text; @@ -120,7 +122,7 @@ export class NotebookMarkdownRenderer { // only remove markdown escapes if it's a hyperlink, filepath usually can start with .{}_ // and the below function escapes them if it encounters in the path. // dev note: using path.isAbsolute instead of isPathLocal since the latter accepts resolver (IRenderMime.IResolver) to check isLocal - if (!path.isAbsolute(href)) { + if (!hrefAbsolute) { href = removeMarkdownEscapes(href); } if ( @@ -143,7 +145,7 @@ export class NotebookMarkdownRenderer { .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); - return `<a href=${href} data-href="${href}" title="${title || href}">${text}</a>`; + return `<a href=${href} data-href="${href}" title="${title || href}" is-absolute=${hrefAbsolute}>${text}</a>`; } }; renderer.paragraph = (text): string => { diff --git a/src/sql/workbench/contrib/notebook/test/browser/htmlMarkdownConverter.test.ts b/src/sql/workbench/contrib/notebook/test/browser/htmlMarkdownConverter.test.ts index 537b99a718..bff18fbf04 100644 --- a/src/sql/workbench/contrib/notebook/test/browser/htmlMarkdownConverter.test.ts +++ b/src/sql/workbench/contrib/notebook/test/browser/htmlMarkdownConverter.test.ts @@ -7,308 +7,313 @@ import * as assert from 'assert'; import { HTMLMarkdownConverter } from 'sql/workbench/contrib/notebook/browser/htmlMarkdownConverter'; import * as path from 'vs/base/common/path'; import { URI } from 'vs/base/common/uri'; +import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; suite('HTML Markdown Converter', function (): void { let htmlMarkdownConverter: HTMLMarkdownConverter; let htmlString: string; + let configurationService: TestConfigurationService; suiteSetup(() => { - htmlMarkdownConverter = new HTMLMarkdownConverter(URI.file('/tmp/notebook.ipynb')); + configurationService = new TestConfigurationService(); + htmlMarkdownConverter = new HTMLMarkdownConverter(URI.file('/tmp/notebook.ipynb'), configurationService); htmlString = ''; }); test('Should not alter HTML with no explicit elements', () => { htmlString = 'Hello World 123'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'No tags test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'No tags test failed'); }); test('Should keep <u> tag intact', () => { htmlString = '<u>Hello test</u>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Basic underline test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Basic underline test failed'); htmlString = 'Hello <u>test</u>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Partial underline test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Partial underline test failed'); htmlString = '<p>Hello <u>test</u></p>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Hello <u>test</u>', 'Partial underline paragraph test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Hello <u>test</u>', 'Partial underline paragraph test failed'); htmlString = '<h1>Hello <u>test</u></h1>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '# Hello <u>test</u>', 'Partial underline h1 test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '# Hello <u>test</u>', 'Partial underline h1 test failed'); htmlString = '<h2>Hello <u>test</u></h2>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '## Hello <u>test</u>', 'Partial underline h2 test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '## Hello <u>test</u>', 'Partial underline h2 test failed'); htmlString = '<h3>Hello <u>test</u></h3>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '### Hello <u>test</u>', 'Partial underline h3 test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '### Hello <u>test</u>', 'Partial underline h3 test failed'); }); test('Should keep <mark> tag intact', () => { htmlString = '<mark>Hello test</mark>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Basic highlight test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Basic highlight test failed'); htmlString = 'Hello <mark>test</mark>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Partial highlight test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Partial highlight test failed'); htmlString = '<p>Hello <mark>test</mark></p>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Hello <mark>test</mark>', 'Partial highlight paragraph test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Hello <mark>test</mark>', 'Partial highlight paragraph test failed'); htmlString = '<h1>Hello <mark>test</mark></h1>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '# Hello <mark>test</mark>', 'Partial highlight h1 test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '# Hello <mark>test</mark>', 'Partial highlight h1 test failed'); htmlString = '<h2>Hello <mark>test</mark></h2>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '## Hello <mark>test</mark>', 'Partial highlight h2 test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '## Hello <mark>test</mark>', 'Partial highlight h2 test failed'); htmlString = '<h3>Hello <mark>test</mark></h3>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '### Hello <mark>test</mark>', 'Partial highlight h3 test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '### Hello <mark>test</mark>', 'Partial highlight h3 test failed'); }); test('Should transform <pre> tag with ```', () => { htmlString = '<pre>Hello test</pre>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '```\nHello test\n```', 'Basic pre test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '```\nHello test\n```', 'Basic pre test failed'); }); test('Should transform <span> tag', () => { htmlString = '<span>Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Hello test', 'Basic span test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Hello test', 'Basic span test failed'); htmlString = 'Yes<span style="background-color: yellow">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes<mark>Hello test</mark>', 'Basic yellow highlight span failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes<mark>Hello test</mark>', 'Basic yellow highlight span failed'); htmlString = 'Yes<span style="background-color:yellow">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes<mark>Hello test</mark>', 'Basic yellow highlight span no space failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes<mark>Hello test</mark>', 'Basic yellow highlight span no space failed'); htmlString = 'Yes<span style="font-weight: bold">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes**Hello test**', 'Basic bold span failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes**Hello test**', 'Basic bold span failed'); htmlString = 'Yes<span style="font-weight:bold">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes**Hello test**', 'Basic bold span no space failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes**Hello test**', 'Basic bold span no space failed'); htmlString = 'Yes<span style="font-style: italic">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes_Hello test_', 'Basic italic span failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes_Hello test_', 'Basic italic span failed'); htmlString = 'Yes<span style="font-style:italic">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes_Hello test_', 'Basic italic span no space failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes_Hello test_', 'Basic italic span no space failed'); htmlString = 'Yes<span style="text-decoration-line: underline">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes<u>Hello test</u>', 'Basic underline span failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes<u>Hello test</u>', 'Basic underline span failed'); htmlString = 'Yes<span style="text-decoration-line:underline">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Yes<u>Hello test</u>', 'Basic underline span no space failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Yes<u>Hello test</u>', 'Basic underline span no space failed'); htmlString = '<h1>Yes<span style="text-decoration-line:underline; font-style:italic; font-weight:bold; background-color: yellow">Hello test</span></h1>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '# Yes<u>_**<mark>Hello test</mark>**_</u>', 'Compound elements span failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '# Yes<u>_**<mark>Hello test</mark>**_</u>', 'Compound elements span failed'); htmlString = '<span style="background-color: yellow;"><b>Hello test</b></span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '<mark>**Hello test**</mark>', 'Span with inner html not parsed correctly'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '<mark>**Hello test**</mark>', 'Span with inner html not parsed correctly'); htmlString = '<b><span style="background-color: yellow;">Hello test</span></b>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**<mark>Hello test</mark>**', 'Span inside bold tag parsed correctly'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**<mark>Hello test</mark>**', 'Span inside bold tag parsed correctly'); htmlString = '<span style="color: orangered">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with color style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with color style should not be altered'); htmlString = '<span style="font-size: 10.0pt">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with font size style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with font size style should not be altered'); htmlString = '<span style="font-size: 10.0pt">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with font size style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with font size style should not be altered'); htmlString = '<span style="background-color: green">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with background color (non yellow) style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with background color (non yellow) style should not be altered'); htmlString = '<span style="background: green">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with background (non yellow) style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with background (non yellow) style should not be altered'); htmlString = '<span style="line-height: 12.0pt">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with line height style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with line height style should not be altered'); htmlString = '<span style="margin-left: 12.0pt">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with margin left style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with margin left style should not be altered'); htmlString = '<span style="margin-bottom: 12.0pt">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with margin bottom style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with margin bottom style should not be altered'); htmlString = '<span style="text-align: center">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with text align style should not be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Span with text align style should not be altered'); htmlString = '<span style="list-style-type: circle">Hello test</span>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Hello test', 'Span with style that is not included in allowlist should be altered'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Hello test', 'Span with style that is not included in allowlist should be altered'); }); test('Should transform <img> tag', () => { htmlString = '<img src="/tmp/stuff.png" alt="stuff">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `![stuff](.${path.sep}stuff.png)`, 'Basic img test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `![stuff](.${path.sep}stuff.png)`, 'Basic img test failed'); htmlString = '<img src="/tmp/stuff.png">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `![](.${path.sep}stuff.png)`, 'Basic img test no alt failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `![](.${path.sep}stuff.png)`, 'Basic img test no alt failed'); htmlString = '<img src="/tmp/my stuff.png">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `![](.${path.sep}my%20stuff.png)`, 'Basic img test no alt space filename failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `![](.${path.sep}my%20stuff.png)`, 'Basic img test no alt space filename failed'); htmlString = '<img src="/tmp/inner/stuff.png" alt="stuff">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `![stuff](.${path.sep}inner${path.sep}stuff.png)`, 'Basic img test below folder failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `![stuff](.${path.sep}inner${path.sep}stuff.png)`, 'Basic img test below folder failed'); htmlString = '<img src="/stuff.png" alt="stuff">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `![stuff](..${path.sep}stuff.png)`, 'Basic img test above folder failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `![stuff](..${path.sep}stuff.png)`, 'Basic img test above folder failed'); // htmlString = '<img src="e:\\some\\other\\path.png">'; - // assert.equal(htmlMarkdownConverter.convert(htmlString), '![](e:\\some\\other\\path.png)', 'img test different drive failed'); + // assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '![](e:\\some\\other\\path.png)', 'img test different drive failed'); htmlString = '<img src="https://www.microsoft.com/images/msft.png" alt="msft">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '![msft](https://www.microsoft.com/images/msft.png)', 'Basic https img test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '![msft](https://www.microsoft.com/images/msft.png)', 'Basic https img test failed'); htmlString = '<img src="http://www.microsoft.com/images/msft.png" alt="msft">'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '![msft](http://www.microsoft.com/images/msft.png)', 'Basic http img test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '![msft](http://www.microsoft.com/images/msft.png)', 'Basic http img test failed'); }); test('Should transform <a> tag', () => { + configurationService.updateValue('notebook.keepAbsolutePath', false, ConfigurationTarget.USER); htmlString = '<a href="/tmp/stuff.png">stuff</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `[stuff](.${path.sep}stuff.png)`, 'Basic link test failed'); - htmlString = '<a href="/tmp/stuff.png"/>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `[](.${path.sep}stuff.png)`, 'Basic link test no label failed'); - htmlString = '<a href="/tmp/my stuff.png"/>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `[](.${path.sep}my%20stuff.png)`, 'Basic link test no label space filename failed'); - htmlString = '<a href="/stuff.png">stuff</a.'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `[stuff](..${path.sep}stuff.png)`, 'Basic link test above folder failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `[stuff](.${path.sep}stuff.png)`, 'Basic link test failed'); + htmlString = '<a href="/tmp/stuff.png"</a>'; + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `[](.${path.sep}stuff.png)`, 'Basic link test no label failed'); + htmlString = '<a href="/tmp/my stuff.png"</a>'; + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `[](.${path.sep}my%20stuff.png)`, 'Basic link test no label space filename failed'); + htmlString = '<a href="/stuff.png">stuff</a>'; + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `[stuff](..${path.sep}stuff.png)`, 'Basic link test above folder failed'); htmlString = '<a href="/tmp/inner/stuff.png">stuff</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `[stuff](.${path.sep}inner${path.sep}stuff.png)`, 'Basic link test below folder failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `[stuff](.${path.sep}inner${path.sep}stuff.png)`, 'Basic link test below folder failed'); // htmlString = '<a href="e:\\some\\other\\path.png"/>'; - // assert.equal(htmlMarkdownConverter.convert(htmlString), '[](e:\\some\\other\\path.png)', 'link test different drive failed'); + // assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '[](e:\\some\\other\\path.png)', 'link test different drive failed'); htmlString = '<a href="https://www.microsoft.com/images/msft.png">msft</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '[msft](https://www.microsoft.com/images/msft.png)', 'Basic https link test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '[msft](https://www.microsoft.com/images/msft.png)', 'Basic https link test failed'); htmlString = '<a href="http://www.microsoft.com/images/msft.png">msft</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '[msft](http://www.microsoft.com/images/msft.png)', 'Basic http link test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '[msft](http://www.microsoft.com/images/msft.png)', 'Basic http link test failed'); htmlString = 'Test <a href="http://www.microsoft.com/images/msft.png">msft</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), 'Test [msft](http://www.microsoft.com/images/msft.png)', 'Basic http link + text test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), 'Test [msft](http://www.microsoft.com/images/msft.png)', 'Basic http link + text test failed'); htmlString = '<a href="#hello">hello</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '[hello](#hello)', 'Basic link to a section failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '[hello](#hello)', 'Basic link to a section failed'); htmlString = '<a href="file.md#hello">hello</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `[hello](.${path.sep}file.md#hello)`, 'Basic anchor link to a section failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `[hello](.${path.sep}file.md#hello)`, 'Basic anchor link to a section failed'); htmlString = '<a href="http://www.microsoft.com/images/msft.png#Hello">hello</a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '[hello](http://www.microsoft.com/images/msft.png#Hello)', 'Http link containing # sign failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '[hello](http://www.microsoft.com/images/msft.png#Hello)', 'Http link containing # sign failed'); }); test('Should transform <li> tags', () => { htmlString = '<ul><li>Test</li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test`, 'Basic unordered list test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Test`, 'Basic unordered list test failed'); htmlString = '<ul><li><span>Test</span><br></li><li>Test2</li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n- Test2`, 'Basic unordered list test with span and line break failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Test\n- Test2`, 'Basic unordered list test with span and line break failed'); htmlString = '<ul><li><span>Test</span><br><br></li><li>Test2</li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test \n \n \n- Test2`, 'Basic unordered list test with span and line break failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Test \n \n \n- Test2`, 'Basic unordered list test with span and line break failed'); htmlString = '<ul><li>Test</li><li>Test2</li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n- Test2`, 'Basic unordered 2 item list test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Test\n- Test2`, 'Basic unordered 2 item list test failed'); htmlString = '<ul><li>Test</li><ul><li>Test2</li></ul><li>Test3</li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n - Test2\n- Test3`, 'Nested item list test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Test\n - Test2\n- Test3`, 'Nested item list test failed'); htmlString = '<ul><li>Test</li><ul><li>Test2</li></ul><ul></ul><li>Test3</li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Test\n - Test2\n- Test3`, 'Nested item list test empty list failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Test\n - Test2\n- Test3`, 'Nested item list test empty list failed'); htmlString = '<ul><li><span>Hello</span><br></li><li><span>Hello</span></li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `- Hello\n- Hello`, 'Nested item list test empty list failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `- Hello\n- Hello`, 'Nested item list test empty list failed'); htmlString = '<ol><li>Test</li></ol>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `1. Test`, 'Basic ordered item test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `1. Test`, 'Basic ordered item test failed'); htmlString = '<ol><li>Test</li><li>Test2</li></ol>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `1. Test\n2. Test2`, 'Basic ordered item test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `1. Test\n2. Test2`, 'Basic ordered item test failed'); htmlString = '<ol><li>Test<ol><li>Test2</li></ol><li>Test3</li></ol>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `1. Test\n 1. Test2\n2. Test3`, 'Basic ordered item test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `1. Test\n 1. Test2\n2. Test3`, 'Basic ordered item test failed'); }); test('Should keep < > tag', () => { htmlString = '<test>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '\\<test\\>', 'Non-HTML tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '\\<test\\>', 'Non-HTML tag test failed to escape'); htmlString = '<test><span style="background:red">message</span><test>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '\\<test\\><span style="background:red">message</span>\\<test\\>', 'Non-HTML tag inside span tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '\\<test\\><span style="background:red">message</span>\\<test\\>', 'Non-HTML tag inside span tag test failed to escape'); htmlString = '<h1><test><h1>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '# \\<test\\>', 'Non-HTML tag inside H1 tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '# \\<test\\>', 'Non-HTML tag inside H1 tag test failed to escape'); htmlString = '<h2><test><h2>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '## \\<test\\>', 'Non-HTML tag inside H2 tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '## \\<test\\>', 'Non-HTML tag inside H2 tag test failed to escape'); htmlString = '<h3><test><h3>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '### \\<test\\>', 'Non-HTML tag inside H3 tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '### \\<test\\>', 'Non-HTML tag inside H3 tag test failed to escape'); htmlString = '<a href="https://www.microsoft.com/images/msft.png"><msft></a>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '[\\<msft\\>](https://www.microsoft.com/images/msft.png)', 'Non-HTML tag as link test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '[\\<msft\\>](https://www.microsoft.com/images/msft.png)', 'Non-HTML tag as link test failed to escape'); htmlString = '<strong><Bold test></strong>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**\\<Bold test\\>**', 'Basic bold non-HTML tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**\\<Bold test\\>**', 'Basic bold non-HTML tag test failed to escape'); htmlString = '<em><Italicize test></em>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_\\<Italicize test\\>_', 'Basic italicize non-HTML tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_\\<Italicize test\\>_', 'Basic italicize non-HTML tag test failed to escape'); htmlString = '<u><Underline_test></u> '; - assert.equal(htmlMarkdownConverter.convert(htmlString), '<u>\\<Underline\\_test\\></u>', 'Basic underline non-HTML tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '<u>\\<Underline\\_test\\></u>', 'Basic underline non-HTML tag test failed to escape'); htmlString = '<ul><li><test></li></ul>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '- \\<test\\>', 'Basic unordered list non-HTML tag item test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '- \\<test\\>', 'Basic unordered list non-HTML tag item test failed to escape'); htmlString = '<ol><li><test></li></ol>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '1. \\<test\\>', 'Basic ordered list non-HTML tag item test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '1. \\<test\\>', 'Basic ordered list non-HTML tag item test failed to escape'); htmlString = '<mark><test></mark>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '<mark>\\<test\\></mark>', 'Basic highlighting Non-HTML tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '<mark>\\<test\\></mark>', 'Basic highlighting Non-HTML tag test failed to escape'); htmlString = '<mark><h1><test></h1></mark>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '<mark>\n\n# \\<test\\>\n\n</mark>', 'Non-HTML tag inside multiple html tags test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '<mark>\n\n# \\<test\\>\n\n</mark>', 'Non-HTML tag inside multiple html tags test failed to escape'); htmlString = '<p><style></p>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '\\<style\\>', 'Style tag as a non-HTML tag test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '\\<style\\>', 'Style tag as a non-HTML tag test failed to escape'); htmlString = '<test> <u>Underlined Text style</u> end'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '\\<test\\> <u>Underlined Text style</u> end', 'Non-HTML tag outside with style and underline test failed to escape'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '\\<test\\> <u>Underlined Text style</u> end', 'Non-HTML tag outside with style and underline test failed to escape'); }); test('Should transform table with no header', () => { htmlString = '<table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with no header failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with no header failed'); }); test('Should transform table with missing headings', () => { htmlString = '<table>\n<thead>\n<tr>\n<th>Test</th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | | |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with missing headings failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | | |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with missing headings failed'); }); test('Should transform table with header', () => { htmlString = '<table>\n<thead>\n<tr>\n<th>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with header failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with header failed'); }); test('Should transform table with no thead', () => { htmlString = '<table>\n<tr>\n<th>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with no thead failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with no thead failed'); }); test('Should transform table with only tbody - typical Office scenario', () => { htmlString = '<table><tbody><tr>\n<td>test1</td>\n<td>test2</td>\n<td>test3</td>\n</tr></tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test1 | test2 | test3 |`, 'One row test with only tbody failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test1 | test2 | test3 |`, 'One row test with only tbody failed'); htmlString = '<table><tbody><tr>\n<td>test1</td>\n</tr></tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| |\n| --- |\n| test1 |`, 'One row one cell test with only tbody failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| |\n| --- |\n| test1 |`, 'One row one cell test with only tbody failed'); htmlString = '<table><tbody><tr>\n<td>test1</td>\n<td>test2</td>\n<td>test3</td>\n</tr>\n<tr>\n<td>test4</td>\n<td>test5</td>\n<td>test6</td>\n</tr>\n<tr>\n<td>test7</td>\n<td>test8</td>\n<td>test9</td>\n</tr>\n<tr>\n<td>test10</td>\n<td>test11</td>\n<td>test12</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test1 | test2 | test3 |\n| test4 | test5 | test6 |\n| test7 | test8 | test9 |\n| test10 | test11 | test12 |`, 'Table with no thead failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test1 | test2 | test3 |\n| test4 | test5 | test6 |\n| test7 | test8 | test9 |\n| test10 | test11 | test12 |`, 'Table with no thead failed'); }); test('Should transform table with paragraph cell correctly', () => { htmlString = '<table><thead><tr><th>Test</th><th>Test2</th></tr></thead><tbody><tr><td><p>testP</p></td><td>test</td></tr></tbody></table>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with simple nested paragraph failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with simple nested paragraph failed'); htmlString = '<table><thead><tr><th><p>Test</p></th><th><p>Test2</p></th></tr></thead><tbody><tr><td><p>testP</p></td><td><p>test</p></td></tr></tbody></table>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with every element with nested paragraph failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with every element with nested paragraph failed'); }); test('Should keep highlight and link tags in tables', () => { htmlString = '<table><thead><tr><th><mark>Test</mark></th><th>Test2</th></tr></thead><tbody><tr><td><p>testP</p></td><td>test</td></tr></tbody></table>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| <mark>Test</mark> | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with simple nested paragraph failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| <mark>Test</mark> | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with simple nested paragraph failed'); htmlString = '<table><thead><tr><th><p><a href="https://www.microsoft.com/">Test</a></p></th><th><p>Test2</p></th></tr></thead><tbody><tr><td><p>testP</p></td><td><p>test</p></td></tr></tbody></table>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| [Test](https://www.microsoft.com/) | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with link in cell failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| [Test](https://www.microsoft.com/) | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with link in cell failed'); }); test('Should transform table with column alignment', () => { htmlString = '<table>\n<thead>\n<tr>\n<th align=right>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --: | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with right align column header failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --: | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with right align column header failed'); htmlString = '<table>\n<thead>\n<tr>\n<th align=left>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| :-- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with left align column header failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| :-- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with left align column header failed'); htmlString = '<table>\n<thead>\n<tr>\n<th align=center>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| :-: | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with center align column header failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| :-: | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with center align column header failed'); }); test('Should transform table to keep <br> for new line in table head and cell', () => { htmlString = '<table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test<br>test</td>\n<td></td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test | test<br>test | |`, 'Table with new line in cell failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test | test<br>test | |`, 'Table with new line in cell failed'); htmlString = '<table>\n<thead>\n<tr>\n<th>TEST<br>TEST</th>\n<th>TEST</th>\n<th>TEST</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n'; - assert.equal(htmlMarkdownConverter.convert(htmlString), `| TEST<br>TEST | TEST | TEST |\n| --- | --- | --- |\n| test | test | test |`, 'Table with new line in table head failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), `| TEST<br>TEST | TEST | TEST |\n| --- | --- | --- |\n| test | test | test |`, 'Table with new line in table head failed'); }); test('Should transform <b> and <strong> tags', () => { htmlString = '<b>test string</b>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic bold test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic bold test failed'); htmlString = '<b style="background-color: yellow">test string</b>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**<mark>test string</mark>**', 'Highlight bold test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**<mark>test string</mark>**', 'Highlight bold test failed'); htmlString = '<b style="background-color: yellow"><i>test string</i></b>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**<mark>_test string_</mark>**', 'Highlight bold italic test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**<mark>_test string_</mark>**', 'Highlight bold italic test failed'); htmlString = '<b style="blah: nothing">test string</b>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Incorrect style bold test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Incorrect style bold test failed'); htmlString = '<strong>test string</strong>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic strong test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic strong test failed'); htmlString = '<strong style="background-color: yellow">test string</strong>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**<mark>test string</mark>**', 'Highlight strong test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**<mark>test string</mark>**', 'Highlight strong test failed'); htmlString = '<strong style="blah: nothing">test string</strong>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Incorrect style strong test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Incorrect style strong test failed'); }); test('Should transform <i> and <em> tags', () => { htmlString = '<i>test string</i>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Basic italic test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Basic italic test failed'); htmlString = '<p><i>test string</i></p>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Basic italic test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Basic italic test failed'); htmlString = '<i style="background-color: yellow">test string</i>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_<mark>test string</mark>_', 'Highlight italic test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_<mark>test string</mark>_', 'Highlight italic test failed'); htmlString = '<i style="background-color: yellow"><b>test string</b></i>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_<mark>**test string**</mark>_', 'Highlight italic bold test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_<mark>**test string**</mark>_', 'Highlight italic bold test failed'); htmlString = '<i style="blah: nothing">test string</i>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Incorrect style italic test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Incorrect style italic test failed'); htmlString = '<em>test string</em>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Basic em test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Basic em test failed'); htmlString = '<em style="background-color: yellow">test string</em>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_<mark>test string</mark>_', 'Highlight em test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_<mark>test string</mark>_', 'Highlight em test failed'); htmlString = '<em style="blah: nothing">test string</em>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Incorrect style em test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_test string_', 'Incorrect style em test failed'); htmlString = '<em style="background-color: yellow"><b>test string</b></em>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '_<mark>**test string**</mark>_', 'Highlight em bold test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '_<mark>**test string**</mark>_', 'Highlight em bold test failed'); }); test('Should transform <u> when necessary', () => { htmlString = '<u>test string</u>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), htmlString, 'Basic underline test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), htmlString, 'Basic underline test failed'); htmlString = '<u style="background-color: yellow">test string</u>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '<u><mark>test string</mark></u>', 'Highlight underline test failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '<u><mark>test string</mark></u>', 'Highlight underline test failed'); htmlString = '<b><u style="background-color: yellow">test string</u></b>'; - assert.equal(htmlMarkdownConverter.convert(htmlString), '**<u><mark>test string</mark></u>**', 'Underline as inner element failed'); + assert.strictEqual(htmlMarkdownConverter.convert(htmlString), '**<u><mark>test string</mark></u>**', 'Underline as inner element failed'); }); }); diff --git a/src/sql/workbench/contrib/notebook/test/browser/notebookLinkHandler.test.ts b/src/sql/workbench/contrib/notebook/test/browser/notebookLinkHandler.test.ts new file mode 100644 index 0000000000..e8e913ba82 --- /dev/null +++ b/src/sql/workbench/contrib/notebook/test/browser/notebookLinkHandler.test.ts @@ -0,0 +1,128 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as path from 'vs/base/common/path'; +import { URI } from 'vs/base/common/uri'; +import { NotebookLinkHandler } from 'sql/workbench/contrib/notebook/browser/notebookLinkHandler'; +import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; + +suite('Noteboook Link Handler', function (): void { + let notebookUri = URI.file('/tmp/notebook.ipynb'); + let configurationService: TestConfigurationService; + + suiteSetup(() => { + configurationService = new TestConfigurationService(); + }); + + test('Should return absolute path and links properly given string link', () => { + let result = new NotebookLinkHandler(notebookUri, 'https://www.microsoft.com/images/msft.png', configurationService); + assert.strictEqual(result.getLinkUrl(), `https://www.microsoft.com/images/msft.png`, 'HTTPS link failed to resolve'); + + result = new NotebookLinkHandler(notebookUri, 'http://www.microsoft.com/images/msft.png', configurationService); + assert.strictEqual(result.getLinkUrl(), `http://www.microsoft.com/images/msft.png`, 'HTTP link failed to resolve'); + + result = new NotebookLinkHandler(notebookUri, `/tmp/stuff.png`, configurationService); + if (process.platform === 'win32') { + assert.strictEqual(result.getLinkUrl(), `/tmp/stuff.png`, 'Basic link test failed'); + } else { + assert.strictEqual(result.getLinkUrl(), `${path.sep}tmp${path.sep}stuff.png`, 'Basic link test failed'); + } + + result = new NotebookLinkHandler(notebookUri, '/stuff.png', configurationService); + if (process.platform === 'win32') { + assert.strictEqual(result.getLinkUrl(), `/stuff.png`, 'Basic link test above folder failed'); + } else { + assert.strictEqual(result.getLinkUrl(), `${path.sep}stuff.png`, 'Basic link test above folder failed'); + } + result = new NotebookLinkHandler(notebookUri, '/tmp/inner/stuff.png', configurationService); + if (process.platform === 'win32') { + assert.strictEqual(result.getLinkUrl(), `/tmp/inner/stuff.png`, 'Basic link test below folder failed'); + } else { + assert.strictEqual(result.getLinkUrl(), `${path.sep}tmp${path.sep}inner${path.sep}stuff.png`, 'Basic link test below folder failed'); + } + }); + + test('Should return relative path and links given anchor element', () => { + let result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: 'https://www.microsoft.com/images/msft.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `https://www.microsoft.com/images/msft.png`, 'HTTPS link failed to resolve'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: 'http://www.microsoft.com/images/msft.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `http://www.microsoft.com/images/msft.png`, 'Basic link test failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/tmp/stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `.${path.sep}stuff.png`, 'Basic link test failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `..${path.sep}stuff.png`, 'Basic link test above folder failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/tmp/inner/stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `.${path.sep}inner${path.sep}stuff.png`, 'Basic link test below folder failed'); + }); + + test('Should return anchor links', () => { + let result = new NotebookLinkHandler(notebookUri, '#hello', configurationService); + assert.strictEqual(result.getLinkUrl(), `#hello`, 'Basic link to a section failed'); + + result = new NotebookLinkHandler(notebookUri, 'file.md#hello', configurationService); + assert.strictEqual(result.getLinkUrl(), `file.md#hello`, 'Basic anchor link to a section failed'); + + result = new NotebookLinkHandler(notebookUri, 'http://www.microsoft.com/images/msft.png#Hello', configurationService); + assert.strictEqual(result.getLinkUrl(), `http://www.microsoft.com/images/msft.png#Hello`, 'Http link containing # sign failed'); + }); + + test('Should return absolute links with keep absolute path setting', () => { + // let basePath = process.cwd(); + configurationService.updateValue('notebook.keepAbsolutePath', true, ConfigurationTarget.USER); + let result = new NotebookLinkHandler(notebookUri, 'https://www.microsoft.com/images/msft.png', configurationService); + assert.strictEqual(result.getLinkUrl(), `https://www.microsoft.com/images/msft.png`, 'HTTPS link failed to resolve'); + + result = new NotebookLinkHandler(notebookUri, 'http://www.microsoft.com/images/msft.png', configurationService); + assert.strictEqual(result.getLinkUrl(), `http://www.microsoft.com/images/msft.png`, 'Basic link test failed'); + + result = new NotebookLinkHandler(notebookUri, '/tmp/stuff.png', configurationService); + if (process.platform === 'win32') { + assert.strictEqual(result.getLinkUrl(), `/tmp/stuff.png`, 'Basic link test failed'); + } else { + assert.strictEqual(result.getLinkUrl(), `${path.sep}tmp${path.sep}stuff.png`, 'Basic link test failed'); + } + + result = new NotebookLinkHandler(notebookUri, '/stuff.png', configurationService); + if (process.platform === 'win32') { + assert.strictEqual(result.getLinkUrl(), `/stuff.png`, 'Basic link test above folder failed'); + } else { + assert.strictEqual(result.getLinkUrl(), `${path.sep}stuff.png`, 'Basic link test above folder failed'); + } + + result = new NotebookLinkHandler(notebookUri, '/tmp/inner/stuff.png', configurationService); + if (process.platform === 'win32') { + assert.strictEqual(result.getLinkUrl(), `/tmp/inner/stuff.png`, 'Basic link test below folder failed'); + } else { + assert.strictEqual(result.getLinkUrl(), `${path.sep}tmp${path.sep}inner${path.sep}stuff.png`, 'Basic link test below folder failed'); + } + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: 'https://www.microsoft.com/images/msft.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `https://www.microsoft.com/images/msft.png`, 'HTTPS link failed to resolve'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: 'http://www.microsoft.com/images/msft.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `http://www.microsoft.com/images/msft.png`, 'Basic link test failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/tmp/stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `.${path.sep}stuff.png`, 'Basic link test failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `..${path.sep}stuff.png`, 'Basic link test above folder failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/tmp/inner/stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `.${path.sep}inner${path.sep}stuff.png`, 'Basic link test below folder failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/tmp/my stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `.${path.sep}my%20stuff.png`, 'Basic link test with space filename failed'); + + result = new NotebookLinkHandler(notebookUri, Object.assign(document.createElement('a'), { href: '/tmp/my%20stuff.png' }), configurationService); + assert.strictEqual(result.getLinkUrl(), `.${path.sep}my%20stuff.png`, 'Basic link test with space filename failed'); + }); +}); diff --git a/src/sql/workbench/contrib/notebook/test/browser/notebookMarkdown.test.ts b/src/sql/workbench/contrib/notebook/test/browser/notebookMarkdown.test.ts index 087b1908cb..7d320350a1 100644 --- a/src/sql/workbench/contrib/notebook/test/browser/notebookMarkdown.test.ts +++ b/src/sql/workbench/contrib/notebook/test/browser/notebookMarkdown.test.ts @@ -49,16 +49,16 @@ suite('NotebookMarkdownRenderer', () => { test('link from local file path', () => { let result: HTMLElement = notebookMarkdownRenderer.renderMarkdown({ value: `[Link to File Path](someFileurl)`, isTrusted: true }); - assert.strictEqual(result.innerHTML, `<p><a href="someFileurl" data-href="someFileurl" title="someFileurl">Link to File Path</a></p>`); + assert.strictEqual(result.innerHTML, `<p><a href="someFileurl" data-href="someFileurl" title="someFileurl" is-absolute="false">Link to File Path</a></p>`); }); test('link from relative file path', () => { notebookMarkdownRenderer.setNotebookURI(URI.parse(`foo/temp/file1.txt`)); - let result: HTMLElement = notebookMarkdownRenderer.renderMarkdown({ value: `[Link to relative path](../test/.build/someimageurl)`, isTrusted: true }); + let result: HTMLElement = notebookMarkdownRenderer.renderMarkdown({ value: `[Link to relative path](../test/build/someimageurl)`, isTrusted: true }); if (process.platform === 'win32') { - assert.strictEqual(result.innerHTML, `<p><a href="\\foo\\test\\.build\\someimageurl" data-href="\\foo\\test\\.build\\someimageurl" title="\\foo\\test\\.build\\someimageurl">Link to relative path</a></p>`); + assert.strictEqual(result.innerHTML, `<p><a href="\\foo\\test\\build\\someimageurl" data-href="\\foo\\test\\build\\someimageurl" title="\\foo\\test\\build\\someimageurl" is-absolute="false">Link to relative path</a></p>`); } else { - assert.strictEqual(result.innerHTML, `<p><a href="/foo/test/.build/someimageurl" data-href="/foo/test/.build/someimageurl" title="/foo/test/.build/someimageurl">Link to relative path</a></p>`); + assert.strictEqual(result.innerHTML, `<p><a href="/foo/test/build/someimageurl" data-href="/foo/test/build/someimageurl" title="/foo/test/build/someimageurl" is-absolute="false">Link to relative path</a></p>`); } }); @@ -71,17 +71,17 @@ suite('NotebookMarkdownRenderer', () => { test('email in markdown format renders properly', () => { let result: HTMLElement = notebookMarkdownRenderer.renderMarkdown({ value: `[test@email.com](mailto:test@email.com)`, isTrusted: true }); - assert.strictEqual(result.innerHTML, `<p><a href="mailto:test@email.com" data-href="mailto:test@email.com" title="mailto:test@email.com">test@email.com</a></p>`); + assert.strictEqual(result.innerHTML, `<p><a href="mailto:test@email.com" data-href="mailto:test@email.com" title="mailto:test@email.com" is-absolute="false">test@email.com</a></p>`); }); test('email inserted directly renders properly', () => { let result: HTMLElement = notebookMarkdownRenderer.renderMarkdown({ value: `test@email.com`, isTrusted: true }); - assert.strictEqual(result.innerHTML, `<p><a href="mailto:test@email.com" data-href="mailto:test@email.com" title="mailto:test@email.com">test@email.com</a></p>`); + assert.strictEqual(result.innerHTML, `<p><a href="mailto:test@email.com" data-href="mailto:test@email.com" title="mailto:test@email.com" is-absolute="false">test@email.com</a></p>`); }); test('link to https with query parameters', () => { let result: HTMLElement = notebookMarkdownRenderer.renderMarkdown({ value: `[test](https://www.test.com?test=&test2=)`, isTrusted: true }); - assert.strictEqual(result.innerHTML, `<p><a href="https://www.test.com?test=&test2=" data-href="https://www.test.com?test=&test2=" title="https://www.test.com?test=&test2=">test</a></p>`); + assert.strictEqual(result.innerHTML, `<p><a href="https://www.test.com?test=&test2=" data-href="https://www.test.com?test=&test2=" title="https://www.test.com?test=&test2=" is-absolute="false">test</a></p>`); }); test('cell attachment image', () => {