vscode-html-languageservice
Advanced tools
Comparing version 1.0.0-next.4 to 1.0.0-next.5
@@ -19,2 +19,5 @@ import { TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, DocumentHighlight, FormattingOptions, MarkedString, DocumentLink } from 'vscode-languageserver-types'; | ||
export declare type HTMLDocument = {}; | ||
export interface DocumentContext { | ||
resolveReference(ref: string): string; | ||
} | ||
export interface LanguageService { | ||
@@ -25,4 +28,4 @@ parseHTMLDocument(document: TextDocument): HTMLDocument; | ||
format(document: TextDocument, range: Range, options: HTMLFormatConfiguration): TextEdit[]; | ||
findDocumentLinks(document: TextDocument, workspacePath: string): DocumentLink[]; | ||
findDocumentLinks(document: TextDocument, documentContext: DocumentContext): DocumentLink[]; | ||
} | ||
export declare function getLanguageService(): LanguageService; |
@@ -6,3 +6,3 @@ (function (factory) { | ||
else if (typeof define === 'function' && define.amd) { | ||
define(["require", "exports", '../parser/htmlScanner', 'vscode-languageserver-types', '../utils/paths', '../utils/strings', 'vscode-uri'], factory); | ||
define(["require", "exports", '../parser/htmlScanner', 'vscode-languageserver-types', 'vscode-uri'], factory); | ||
} | ||
@@ -17,4 +17,2 @@ })(function (require, exports) { | ||
var vscode_languageserver_types_1 = require('vscode-languageserver-types'); | ||
var paths = require('../utils/paths'); | ||
var strings = require('../utils/strings'); | ||
var vscode_uri_1 = require('vscode-uri'); | ||
@@ -26,11 +24,12 @@ function stripQuotes(url) { | ||
} | ||
function getWorkspaceUrl(modelAbsoluteUri, rootAbsoluteUrl, tokenContent) { | ||
function getWorkspaceUrl(modelAbsoluteUri, tokenContent, documentContext) { | ||
if (/^\s*javascript\:/i.test(tokenContent) || /^\s*\#/i.test(tokenContent)) { | ||
return null; | ||
} | ||
if (/^\s*https?:\/\//i.test(tokenContent) || /^\s*file:\/\//i.test(tokenContent)) { | ||
tokenContent = tokenContent.replace(/^\s*/g, ''); | ||
if (/^https?:\/\//i.test(tokenContent) || /^file:\/\//i.test(tokenContent)) { | ||
// Absolute link that needs no treatment | ||
return tokenContent.replace(/^\s*/g, ''); | ||
return tokenContent; | ||
} | ||
if (/^\s*\/\//i.test(tokenContent)) { | ||
if (/^\/\//i.test(tokenContent)) { | ||
// Absolute link (that does not name the protocol) | ||
@@ -43,25 +42,8 @@ var pickedScheme = 'http'; | ||
} | ||
var modelPath = paths.dirname(modelAbsoluteUri.path); | ||
var alternativeResultPath = null; | ||
if (tokenContent.length > 0 && tokenContent.charAt(0) === '/') { | ||
alternativeResultPath = tokenContent; | ||
if (documentContext) { | ||
return documentContext.resolveReference(tokenContent); | ||
} | ||
else { | ||
alternativeResultPath = paths.join(modelPath, tokenContent); | ||
alternativeResultPath = alternativeResultPath.replace(/^(\/\.\.)+/, ''); | ||
} | ||
var potentialResult = modelAbsoluteUri.with({ path: alternativeResultPath }).toString(true); | ||
var rootAbsoluteUrlStr = rootAbsoluteUrl && rootAbsoluteUrl.toString(true); | ||
if (rootAbsoluteUrlStr && strings.startsWith(modelAbsoluteUri.toString(true), rootAbsoluteUrlStr)) { | ||
// The `rootAbsoluteUrl` is set and matches our current model | ||
// We need to ensure that this `potentialResult` does not escape `rootAbsoluteUrl` | ||
var commonPrefixLength = strings.commonPrefixLength(rootAbsoluteUrlStr, potentialResult); | ||
if (strings.endsWith(rootAbsoluteUrlStr, '/')) { | ||
commonPrefixLength = potentialResult.lastIndexOf('/', commonPrefixLength) + 1; | ||
} | ||
return rootAbsoluteUrlStr + potentialResult.substr(commonPrefixLength); | ||
} | ||
return potentialResult; | ||
return tokenContent; | ||
} | ||
function createLink(document, rootAbsoluteUrl, attributeValue, startOffset, endOffset) { | ||
function createLink(document, documentContext, attributeValue, startOffset, endOffset) { | ||
var documentUri = vscode_uri_1.default.parse(document.uri); | ||
@@ -73,3 +55,3 @@ var tokenContent = stripQuotes(attributeValue); | ||
} | ||
var workspaceUrl = getWorkspaceUrl(documentUri, rootAbsoluteUrl, tokenContent); | ||
var workspaceUrl = getWorkspaceUrl(documentUri, tokenContent, documentContext); | ||
if (!workspaceUrl) { | ||
@@ -83,12 +65,5 @@ return null; | ||
} | ||
function findDocumentLinks(document, workspacePath) { | ||
function findDocumentLinks(document, documentContext) { | ||
var newLinks = []; | ||
var rootAbsoluteUrl = null; | ||
if (workspacePath) { | ||
// The workspace can be null in the no folder opened case | ||
if (workspacePath.charAt(workspacePath.length - 1) !== '/') { | ||
workspacePath = workspacePath + '/'; | ||
} | ||
rootAbsoluteUrl = vscode_uri_1.default.parse(workspacePath); | ||
} | ||
var scanner = htmlScanner_1.createScanner(document.getText(), 0); | ||
@@ -106,3 +81,3 @@ var token = scanner.scan(); | ||
var attributeValue = scanner.getTokenText(); | ||
var link = createLink(document, rootAbsoluteUrl, attributeValue, scanner.getTokenOffset(), scanner.getTokenEnd()); | ||
var link = createLink(document, documentContext, attributeValue, scanner.getTokenOffset(), scanner.getTokenEnd()); | ||
if (link) { | ||
@@ -109,0 +84,0 @@ newLinks.push(link); |
@@ -6,3 +6,3 @@ (function (factory) { | ||
else if (typeof define === 'function' && define.amd) { | ||
define(["require", "exports", 'assert', 'vscode-languageserver-types', '../htmlLanguageService'], factory); | ||
define(["require", "exports", 'assert', 'vscode-languageserver-types', '../htmlLanguageService', 'url'], factory); | ||
} | ||
@@ -18,7 +18,11 @@ })(function (require, exports) { | ||
var htmlLanguageService = require('../htmlLanguageService'); | ||
var url = require('url'); | ||
suite('HTML Link Detection', function () { | ||
function testLinkCreation(modelUrl, rootUrl, tokenContent, expected) { | ||
function testLinkCreation(modelUrl, tokenContent, expected) { | ||
var documentContext = { | ||
resolveReference: function (ref) { return url.resolve(modelUrl, ref); } | ||
}; | ||
var document = vscode_languageserver_types_1.TextDocument.create(modelUrl, 'html', 0, "<a href=\"" + tokenContent + "\">"); | ||
var ls = htmlLanguageService.getLanguageService(); | ||
var links = ls.findDocumentLinks(document, rootUrl); | ||
var links = ls.findDocumentLinks(document, documentContext); | ||
assert.equal(links[0] && links[0].target, expected); | ||
@@ -28,49 +32,36 @@ } | ||
var document = vscode_languageserver_types_1.TextDocument.create('test://test/test.html', 'html', 0, value); | ||
var documentContext = { | ||
resolveReference: function (ref) { return url.resolve(document.uri, ref); } | ||
}; | ||
var ls = htmlLanguageService.getLanguageService(); | ||
var links = ls.findDocumentLinks(document, 'test://test'); | ||
var links = ls.findDocumentLinks(document, documentContext); | ||
assert.deepEqual(links.map(function (l) { return l.range.start.character; }), expectedLinkLocations); | ||
} | ||
test('Link creation', function () { | ||
testLinkCreation('inmemory://model/1', null, 'javascript:void;', null); | ||
testLinkCreation('inmemory://model/1', null, ' \tjavascript:alert(7);', null); | ||
testLinkCreation('inmemory://model/1', null, ' #relative', null); | ||
testLinkCreation('inmemory://model/1', null, 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('inmemory://model/1', null, 'http://www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('inmemory://model/1', null, 'https://www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('inmemory://model/1', null, '//www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('inmemory://model/1', null, '../../a.js', 'inmemory://model/a.js'); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', 'javascript:void;', null); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', ' \tjavascript:alert(7);', null); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', ' #relative', null); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', 'http://www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', 'https://www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', ' //www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('inmemory://model/1', 'inmemory://model/', '../../a.js', 'inmemory://model/a.js'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'javascript:void;', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, ' \tjavascript:alert(7);', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, ' #relative', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'http://www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'https://www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, ' //www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'a.js', 'file:///c:/Alex/src/path/to/a.js'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, '/a.js', 'file:///a.js'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'javascript:void;', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', ' \tjavascript:alert(7);', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', ' #relative', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'http://www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'https://www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'https://www.microsoft.com/?q=1#h', 'https://www.microsoft.com/?q=1#h'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', ' //www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'a.js', 'file:///c:/Alex/src/path/to/a.js'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', '/a.js', 'file:///c:/Alex/src/a.js'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', null, 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', null, '//www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', 'https://www.test.com', '//www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('http://model/1', 'javascript:void;', null); | ||
testLinkCreation('http://model/1', ' \tjavascript:alert(7);', null); | ||
testLinkCreation('http://model/1', ' #relative', null); | ||
testLinkCreation('http://model/1', 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('http://model/1', 'http://www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('http://model/1', 'https://www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('http://model/1', '//www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('http://model/x/1', 'a.js', 'http://model/x/a.js'); | ||
testLinkCreation('http://model/x/1', '/b.js', 'http://model/b.js'); | ||
testLinkCreation('http://model/x/y/1', '../../c.js', 'http://model/c.js'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'javascript:void;', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', ' \tjavascript:alert(7);', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', ' #relative', null); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'http://www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'https://www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', ' //www.microsoft.com/', 'http://www.microsoft.com/'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'a.js', 'file:///C:/Alex/src/path/to/a.js'); | ||
testLinkCreation('file:///C:/Alex/src/path/to/file.txt', '/a.js', 'file:///a.js'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', '//www.microsoft.com/', 'https://www.microsoft.com/'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', '//www.microsoft.com/', 'https://www.microsoft.com/'); | ||
// invalid uris don't throw | ||
testLinkCreation('https://www.test.com/path/to/file.txt', 'https://www.test.com', '%', 'https://www.test.com/path/to/%'); | ||
testLinkCreation('https://www.test.com/path/to/file.txt', '%', 'https://www.test.com/path/to/%'); | ||
// Bug #18314: Ctrl + Click does not open existing file if folder's name starts with 'c' character | ||
testLinkCreation('file:///c:/Alex/working_dir/18314-link-detection/test.html', 'file:///c:/Alex/working_dir/18314-link-detection/', '/class/class.js', 'file:///c:/Alex/working_dir/18314-link-detection/class/class.js'); | ||
testLinkCreation('file:///c:/Alex/working_dir/18314-link-detection/test.html', '/class/class.js', 'file:///class/class.js'); | ||
}); | ||
@@ -77,0 +68,0 @@ test('Link detection', function () { |
{ | ||
"name": "vscode-html-languageservice", | ||
"version": "1.0.0-next.4", | ||
"version": "1.0.0-next.5", | ||
"description": "Language service for HTML", | ||
@@ -5,0 +5,0 @@ "main": "./lib/htmlLanguageService.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
276364
4531