diff --git a/extensions/markdown-language-features/.vscodeignore b/extensions/markdown-language-features/.vscodeignore index 30d948fbc66..bcb886a094d 100644 --- a/extensions/markdown-language-features/.vscodeignore +++ b/extensions/markdown-language-features/.vscodeignore @@ -4,6 +4,7 @@ tsconfig.json out/test/** out/** extension.webpack.config.js +extension-browser.webpack.config.js cgmanifest.json yarn.lock preview-src/** diff --git a/extensions/markdown-language-features/extension-browser.webpack.config.js b/extensions/markdown-language-features/extension-browser.webpack.config.js new file mode 100644 index 00000000000..60d61c13dec --- /dev/null +++ b/extensions/markdown-language-features/extension-browser.webpack.config.js @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../shared.webpack.config'); +const path = require('path'); + +const clientConfig = withDefaults({ + context: __dirname, + target: 'webworker', + entry: { + extension: './src/extension.ts' + }, + resolve: { + alias: { + 'vscode-extension-telemetry': path.resolve(__dirname, 'polyfills/vscode-extension-telemetry.js'), + 'vscode-nls': path.resolve(__dirname, 'polyfills/vscode-nls.js'), + }, + } +}); + +clientConfig.module.rules[0].use.shift(); // remove nls loader + +module.exports = clientConfig; diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 6d7b078caad..01bb8a06d03 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -12,6 +12,7 @@ "vscode": "^1.20.0" }, "main": "./out/extension", + "browser": "./dist/extension.js", "categories": [ "Programming Languages" ], @@ -327,7 +328,9 @@ "watch": "npm run build-preview && gulp watch-extension:markdown-language-features", "vscode:prepublish": "npm run build-ext && npm run build-preview", "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown-language-features ./tsconfig.json", - "build-preview": "webpack --mode production" + "build-preview": "webpack --mode production", + "compile-web": "npx webpack-cli --config extension-browser.webpack.config --mode none", + "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { "highlight.js": "9.15.10", diff --git a/extensions/markdown-language-features/polyfills/vscode-extension-telemetry.js b/extensions/markdown-language-features/polyfills/vscode-extension-telemetry.js new file mode 100644 index 00000000000..d038776c59c --- /dev/null +++ b/extensions/markdown-language-features/polyfills/vscode-extension-telemetry.js @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); + +let TelemetryReporter = (function () { + function TelemetryReporter(extensionId, extensionVersion, key) { + } + TelemetryReporter.prototype.updateUserOptIn = function (key) { + }; + TelemetryReporter.prototype.createAppInsightsClient = function (key) { + }; + TelemetryReporter.prototype.getCommonProperties = function () { + }; + TelemetryReporter.prototype.sendTelemetryEvent = function (eventName, properties, measurements) { + }; + TelemetryReporter.prototype.dispose = function () { + }; + TelemetryReporter.TELEMETRY_CONFIG_ID = 'telemetry'; + TelemetryReporter.TELEMETRY_CONFIG_ENABLED_ID = 'enableTelemetry'; + return TelemetryReporter; +}()); +exports.default = TelemetryReporter; diff --git a/extensions/markdown-language-features/polyfills/vscode-nls.js b/extensions/markdown-language-features/polyfills/vscode-nls.js new file mode 100644 index 00000000000..b89250102af --- /dev/null +++ b/extensions/markdown-language-features/polyfills/vscode-nls.js @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); + +function format(message, args) { + let result; + // if (isPseudo) { + // // FF3B and FF3D is the Unicode zenkaku representation for [ and ] + // message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; + // } + if (args.length === 0) { + result = message; + } + else { + result = message.replace(/\{(\d+)\}/g, function (match, rest) { + let index = rest[0]; + let arg = args[index]; + let replacement = match; + if (typeof arg === 'string') { + replacement = arg; + } + else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) { + replacement = String(arg); + } + return replacement; + }); + } + return result; +} + +function localize(key, message) { + let args = []; + for (let _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + return format(message, args); +} + +function loadMessageBundle(file) { + return localize; +} + +let MessageFormat; +(function (MessageFormat) { + MessageFormat["file"] = "file"; + MessageFormat["bundle"] = "bundle"; + MessageFormat["both"] = "both"; +})(MessageFormat = exports.MessageFormat || (exports.MessageFormat = {})); +let BundleFormat; +(function (BundleFormat) { + // the nls.bundle format + BundleFormat["standalone"] = "standalone"; + BundleFormat["languagePack"] = "languagePack"; +})(BundleFormat = exports.BundleFormat || (exports.BundleFormat = {})); + +exports.loadMessageBundle = loadMessageBundle; +function config(opts) { + if (opts) { + if (isString(opts.locale)) { + options.locale = opts.locale.toLowerCase(); + options.language = options.locale; + resolvedLanguage = undefined; + resolvedBundles = Object.create(null); + } + if (opts.messageFormat !== undefined) { + options.messageFormat = opts.messageFormat; + } + if (opts.bundleFormat === BundleFormat.standalone && options.languagePackSupport === true) { + options.languagePackSupport = false; + } + } + isPseudo = options.locale === 'pseudo'; + return loadMessageBundle; +} +exports.config = config; diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index c500b692eaa..ed0cee54457 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -3,14 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as crypto from 'crypto'; -import * as path from 'path'; import { MarkdownIt, Token } from 'markdown-it'; +import * as path from 'path'; import * as vscode from 'vscode'; import { MarkdownContributionProvider as MarkdownContributionProvider } from './markdownExtensions'; import { Slugifier } from './slugify'; import { SkinnyTextDocument } from './tableOfContentsProvider'; -import { MarkdownFileExtensions, Schemes, isOfScheme } from './util/links'; +import { hash } from './util/hash'; +import { isOfScheme, MarkdownFileExtensions, Schemes } from './util/links'; const UNICODE_NEWLINE_REGEX = /\u2028|\u2029/g; @@ -197,9 +197,7 @@ export class MarkdownEngine { const src = token.attrGet('src'); if (src) { - const hash = crypto.createHash('sha256'); - hash.update(src); - const imgHash = hash.digest('hex'); + const imgHash = hash(src); token.attrSet('id', `image-hash-${imgHash}`); } diff --git a/extensions/markdown-language-features/src/util/hash.ts b/extensions/markdown-language-features/src/util/hash.ts new file mode 100644 index 00000000000..b009808968d --- /dev/null +++ b/extensions/markdown-language-features/src/util/hash.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Return a hash value for an object. + */ +export function hash(obj: any, hashVal = 0): number { + switch (typeof obj) { + case 'object': + if (obj === null) { + return numberHash(349, hashVal); + } else if (Array.isArray(obj)) { + return arrayHash(obj, hashVal); + } + return objectHash(obj, hashVal); + case 'string': + return stringHash(obj, hashVal); + case 'boolean': + return booleanHash(obj, hashVal); + case 'number': + return numberHash(obj, hashVal); + case 'undefined': + return 937 * 31; + default: + return numberHash(obj, 617); + } +} + +function numberHash(val: number, initialHashVal: number): number { + return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32 +} + +function booleanHash(b: boolean, initialHashVal: number): number { + return numberHash(b ? 433 : 863, initialHashVal); +} + +function stringHash(s: string, hashVal: number) { + hashVal = numberHash(149417, hashVal); + for (let i = 0, length = s.length; i < length; i++) { + hashVal = numberHash(s.charCodeAt(i), hashVal); + } + return hashVal; +} + +function arrayHash(arr: any[], initialHashVal: number): number { + initialHashVal = numberHash(104579, initialHashVal); + return arr.reduce((hashVal, item) => hash(item, hashVal), initialHashVal); +} + +function objectHash(obj: any, initialHashVal: number): number { + initialHashVal = numberHash(181387, initialHashVal); + return Object.keys(obj).sort().reduce((hashVal, key) => { + hashVal = stringHash(key, hashVal); + return hash(obj[key], hashVal); + }, initialHashVal); +}