diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 3dfc882b432..4b303046a26 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -508,7 +508,7 @@ "@emmetio/html-matcher": "^0.3.3", "@emmetio/math-expression": "^1.0.4", "@vscode/emmet-helper": "^2.3.0", - "image-size": "^0.5.2", + "image-size": "~1.0.0", "vscode-languageserver-textdocument": "^1.0.1" }, "capabilities": { diff --git a/extensions/emmet/src/imageSizeHelper.ts b/extensions/emmet/src/imageSizeHelper.ts index c761b095b5e..b012ab624ee 100644 --- a/extensions/emmet/src/imageSizeHelper.ts +++ b/extensions/emmet/src/imageSizeHelper.ts @@ -8,16 +8,23 @@ import * as path from 'path'; import * as http from 'http'; import * as https from 'https'; -import { parse as parseUrl } from 'url'; -import * as sizeOf from 'image-size'; +import { URL } from 'url'; +import { imageSize } from 'image-size'; +import { ISizeCalculationResult } from 'image-size/dist/types/interface'; const reUrl = /^https?:/; +export type ImageInfoWithScale = { + realWidth: number, + realHeight: number, + width: number, + height: number +}; /** * Get size of given image file. Supports files from local filesystem, * as well as URLs */ -export function getImageSize(file: string) { +export function getImageSize(file: string): Promise { file = file.replace(/^file:\/\//, ''); return reUrl.test(file) ? getImageSizeFromURL(file) : getImageSizeFromFile(file); } @@ -25,7 +32,7 @@ export function getImageSize(file: string) { /** * Get image size from file on local file system */ -function getImageSizeFromFile(file: string) { +function getImageSizeFromFile(file: string): Promise { return new Promise((resolve, reject) => { const isDataUrl = file.match(/^data:.+?;base64,/); @@ -33,13 +40,13 @@ function getImageSizeFromFile(file: string) { // NB should use sync version of `sizeOf()` for buffers try { const data = Buffer.from(file.slice(isDataUrl[0].length), 'base64'); - return resolve(sizeForFileName('', sizeOf(data))); + return resolve(sizeForFileName('', imageSize(data))); } catch (err) { return reject(err); } } - sizeOf(file, (err: any, size: any) => { + imageSize(file, (err: Error | null, size?: ISizeCalculationResult) => { if (err) { reject(err); } else { @@ -52,9 +59,9 @@ function getImageSizeFromFile(file: string) { /** * Get image size from given remove URL */ -function getImageSizeFromURL(urlStr: string) { +function getImageSizeFromURL(urlStr: string): Promise { return new Promise((resolve, reject) => { - const url = parseUrl(urlStr); + const url = new URL(urlStr); const getTransport = url.protocol === 'https:' ? https.get : http.get; if (!url.pathname) { @@ -62,13 +69,13 @@ function getImageSizeFromURL(urlStr: string) { } const urlPath: string = url.pathname; - getTransport(url as any, resp => { + getTransport(url, resp => { const chunks: Buffer[] = []; let bufSize = 0; const trySize = (chunks: Buffer[]) => { try { - const size = sizeOf(Buffer.concat(chunks, bufSize)); + const size: ISizeCalculationResult = imageSize(Buffer.concat(chunks, bufSize)); resp.removeListener('data', onData); resp.destroy(); // no need to read further resolve(sizeForFileName(path.basename(urlPath), size)); @@ -90,8 +97,7 @@ function getImageSizeFromURL(urlStr: string) { resp.removeListener('data', onData); reject(err); }); - }) - .once('error', reject); + }).once('error', reject); }); } @@ -99,10 +105,14 @@ function getImageSizeFromURL(urlStr: string) { * Returns size object for given file name. If file name contains `@Nx` token, * the final dimentions will be downscaled by N */ -function sizeForFileName(fileName: string, size: any) { +function sizeForFileName(fileName: string, size?: ISizeCalculationResult): ImageInfoWithScale | undefined { const m = fileName.match(/@(\d+)x\./); const scale = m ? +m[1] : 1; + if (!size || !size.width || !size.height) { + return; + } + return { realWidth: size.width, realHeight: size.height, diff --git a/extensions/emmet/src/test/updateImageSize.test.ts b/extensions/emmet/src/test/updateImageSize.test.ts index 9023285807b..37f5653c574 100644 --- a/extensions/emmet/src/test/updateImageSize.test.ts +++ b/extensions/emmet/src/test/updateImageSize.test.ts @@ -9,22 +9,26 @@ import { Selection } from 'vscode'; import { withRandomFileEditor, closeAllEditors } from './testUtils'; import { updateImageSize } from '../updateImageSize'; -suite.skip('Tests for Emmet actions on html tags', () => { +suite('Tests for Emmet actions on html tags', () => { teardown(closeAllEditors); + const imageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYcAAB2HAY/l8WUAAAATSURBVBhXY/jPwADGDP////8PAB/uBfuDMzhuAAAAAElFTkSuQmCC'; + const imageWidth = 2; + const imageHeight = 2; + test('update image css with multiple cursors in css file', () => { const cssContents = ` .one { margin: 10px; padding: 10px; - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); + background-image: url('${imageUrl}'); } .two { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); + background-image: url('${imageUrl}'); height: 42px; } .three { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); + background-image: url('${imageUrl}'); width: 42px; } `; @@ -32,19 +36,19 @@ suite.skip('Tests for Emmet actions on html tags', () => { .one { margin: 10px; padding: 10px; - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); - width: 1024px; - height: 1024px; + background-image: url('${imageUrl}'); + width: ${imageWidth}px; + height: ${imageHeight}px; } .two { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); - width: 1024px; - height: 1024px; + background-image: url('${imageUrl}'); + width: ${imageWidth}px; + height: ${imageHeight}px; } .three { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); - height: 1024px; - width: 1024px; + background-image: url('${imageUrl}'); + height: ${imageHeight}px; + width: ${imageWidth}px; } `; return withRandomFileEditor(cssContents, 'css', (editor, doc) => { @@ -68,14 +72,14 @@ suite.skip('Tests for Emmet actions on html tags', () => { .one { margin: 10px; padding: 10px; - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); + background-image: url('${imageUrl}'); } .two { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); + background-image: url('${imageUrl}'); height: 42px; } .three { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); + background-image: url('${imageUrl}'); width: 42px; } @@ -87,19 +91,19 @@ suite.skip('Tests for Emmet actions on html tags', () => { .one { margin: 10px; padding: 10px; - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); - width: 1024px; - height: 1024px; + background-image: url('${imageUrl}'); + width: ${imageWidth}px; + height: ${imageHeight}px; } .two { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); - width: 1024px; - height: 1024px; + background-image: url('${imageUrl}'); + width: ${imageWidth}px; + height: ${imageHeight}px; } .three { - background-image: url(https://raw.githubusercontent.com/microsoft/vscode/master/resources/linux/code.png); - height: 1024px; - width: 1024px; + background-image: url('${imageUrl}'); + height: ${imageHeight}px; + width: ${imageWidth}px; } @@ -121,16 +125,16 @@ suite.skip('Tests for Emmet actions on html tags', () => { test('update image size in img tag in html file with multiple cursors', () => { const htmlwithimgtag = ` - - - + + + `; const expectedContents = ` - - - + + + `; return withRandomFileEditor(htmlwithimgtag, 'html', (editor, doc) => { diff --git a/extensions/emmet/src/typings/image-size.d.ts b/extensions/emmet/src/typings/image-size.d.ts deleted file mode 100644 index f9a935ea050..00000000000 --- a/extensions/emmet/src/typings/image-size.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Type definitions for image-size -// Project: https://github.com/image-size/image-size -// Definitions by: Elisée MAURER -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -/// - -declare module 'image-size' { - interface ImageInfo { - width: number; - height: number; - type: string; - } - - function sizeOf(path: string): ImageInfo; - function sizeOf(path: string, callback: (err: Error, dimensions: ImageInfo) => void): void; - - function sizeOf(buffer: Buffer): ImageInfo; - - namespace sizeOf { } - - export = sizeOf; -} diff --git a/extensions/emmet/src/updateImageSize.ts b/extensions/emmet/src/updateImageSize.ts index dadfe49fd89..3a9204c0580 100644 --- a/extensions/emmet/src/updateImageSize.ts +++ b/extensions/emmet/src/updateImageSize.ts @@ -7,7 +7,7 @@ import { TextEditor, Position, window, TextEdit } from 'vscode'; import * as path from 'path'; -import { getImageSize } from './imageSizeHelper'; +import { getImageSize, ImageInfoWithScale } from './imageSizeHelper'; import { getFlatNode, iterateCSSToken, getCssPropertyFromRule, isStyleSheet, validate, offsetRangeToVsRange } from './util'; import { HtmlNode, CssToken, HtmlToken, Attribute, Property } from 'EmmetFlatNode'; import { locateFile } from './locateFile'; @@ -108,11 +108,11 @@ function updateImageSizeCSS(editor: TextEditor, position: Position, fetchNode: ( return locateFile(path.dirname(editor.document.fileName), src) .then(getImageSize) - .then((size: any): TextEdit[] => { + .then((size: ImageInfoWithScale | undefined): TextEdit[] => { // since this action is asynchronous, we have to ensure that editor wasn't // changed and user didn't moved caret outside node const prop = fetchNode(editor, position); - if (prop && getImageSrcCSS(editor, prop, position) === src) { + if (size && prop && getImageSrcCSS(editor, prop, position) === src) { return updateCSSNode(editor, prop, size.width, size.height); } return []; diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index 020bf7b0777..d6b16338584 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -78,16 +78,30 @@ emmet@^2.3.0: "@emmetio/abbreviation" "^2.2.2" "@emmetio/css-abbreviation" "^2.1.4" -image-size@^0.5.2: - version "0.5.5" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" - integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= +image-size@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.0.tgz#58b31fe4743b1cec0a0ac26f5c914d3c5b2f0750" + integrity sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw== + dependencies: + queue "6.0.2" + +inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== jsonc-parser@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342" integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== +queue@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65" + integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA== + dependencies: + inherits "~2.0.3" + vscode-languageserver-textdocument@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.2.tgz#2f9f6bd5b5eb3d8e21424c0c367009216f016236"