diff --git a/package-lock.json b/package-lock.json index c30f80fa..60264165 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ace-linters-root", - "version": "2.3.0", + "version": "2.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ace-linters-root", - "version": "2.3.0", + "version": "2.3.1", "workspaces": [ "./packages/*" ], @@ -2519,6 +2519,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -4374,6 +4382,16 @@ "url": "https://bevry.me/fund" } }, + "node_modules/dompurify": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dt-sql-parser": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/dt-sql-parser/-/dt-sql-parser-4.4.0.tgz", @@ -7208,6 +7226,19 @@ "dev": true, "license": "ISC" }, + "node_modules/marked": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.0.tgz", + "integrity": "sha512-2e7Qiv/HJSXj8rDEpgTvGKsP8yYtI9xXHKDnrftrmnrJPaFNM7VRb2YCzWaX4BP1iCJ/XPduzDJZMFoqTCcIMA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -9099,30 +9130,6 @@ "node": ">=8" } }, - "node_modules/showdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", - "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", - "dev": true, - "dependencies": { - "commander": "^9.0.0" - }, - "bin": { - "showdown": "bin/showdown.js" - }, - "funding": { - "type": "individual", - "url": "https://www.paypal.me/tiviesantos" - } - }, - "node_modules/showdown/node_modules/commander": { - "version": "9.5.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -10694,7 +10701,7 @@ } }, "packages/ace-linters": { - "version": "2.1.2", + "version": "2.1.3", "license": "MIT", "dependencies": { "vscode-languageserver-protocol": "^3.17.5", @@ -10713,15 +10720,16 @@ "ace-builds": "^1.39.0", "ace-code": "^1.39.0", "chai": "^4.3.7", + "dompurify": "^3.3.3", "dts-bundle-generator": "^9.5.1", "htmlhint": "^1.9.2", "http-server": "^14.1.1", "luaparse": "^0.3.1", + "marked": "^18.0.0", "mocha": "^10.2.0", "nyc": "^15.1.0", "php-parser": "^3.4.0", "rimraf": "^5.0.0", - "showdown": "^2.1.0", "ts-node": "^10.9.1", "vite": "^8.0.0", "vite-plugin-node-polyfills": "^0.25.0", diff --git a/package.json b/package.json index 4f718677..dd8f9c77 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ace-linters-root", - "version": "2.3.0", + "version": "2.3.1", "scripts": { "build:parts": "npm run build -ws", "build": "npm run build:parts && vite build", diff --git a/packages/ace-linters/package.json b/packages/ace-linters/package.json index d92a540f..e42a959d 100644 --- a/packages/ace-linters/package.json +++ b/packages/ace-linters/package.json @@ -1,7 +1,7 @@ { "name": "ace-linters", "author": "Azat Alimov ", - "version": "2.1.2", + "version": "2.1.3", "scripts": { "clean": "rimraf build", "postbuild": "node postbuild.js", @@ -29,7 +29,8 @@ "vscode-css-languageservice": "^6.3.10", "vscode-json-languageservice": "^5.7.2", "luaparse": "^0.3.1", - "showdown": "^2.1.0", + "marked": "^18.0.0", + "dompurify": "^3.3.3", "vscode-ws-jsonrpc": "^3.4.0", "htmlhint": "^1.9.2", "@xml-tools/constraints": "^1.1.1", diff --git a/packages/ace-linters/src/ace/hover-tooltip.ts b/packages/ace-linters/src/ace/hover-tooltip.ts index 512ee28d..6aefe215 100644 --- a/packages/ace-linters/src/ace/hover-tooltip.ts +++ b/packages/ace-linters/src/ace/hover-tooltip.ts @@ -204,8 +204,9 @@ export class HoverTooltip extends Tooltip { element.style.display = "block"; this.$setPosition(editor, position, true, range); - - editor.renderer["$textLayer"].dom.$fixPositionBug(element); + if (editor.renderer["$textLayer"].dom.$fixPositionBug) { + editor.renderer["$textLayer"].dom.$fixPositionBug(element); + } popupManager.addPopup(this); } diff --git a/packages/ace-linters/src/components/markdownConverter.ts b/packages/ace-linters/src/components/markdownConverter.ts new file mode 100644 index 00000000..577ec057 --- /dev/null +++ b/packages/ace-linters/src/components/markdownConverter.ts @@ -0,0 +1,9 @@ +import {MarkDownConverter} from "../types/converters"; +import {marked} from "marked"; +import DOMPurify from 'dompurify'; + +export const defaultMarkdownConverter: MarkDownConverter = { + makeHtml(markdownText: string) { + return DOMPurify.sanitize(marked.parse(markdownText, {async: false})); + } +} \ No newline at end of file diff --git a/packages/ace-linters/src/language-provider.ts b/packages/ace-linters/src/language-provider.ts index da0bb48d..cea69e56 100644 --- a/packages/ace-linters/src/language-provider.ts +++ b/packages/ace-linters/src/language-provider.ts @@ -15,7 +15,6 @@ import { } from "./type-converters/lsp/lsp-converters"; import * as lsp from "vscode-languageserver-protocol"; -import showdown from "showdown"; import {createWorker} from "./cdn-worker"; import {SignatureTooltip} from "./components/signature-tooltip"; import { @@ -40,6 +39,7 @@ import {popupManager} from "./ace/popupManager"; import {extractDiagnosticQuickFixesAtPosition} from "./components/hover/hover-quick-fixes"; import {resolveHoverModel} from "./components/hover/hover-data-resolver"; import {createHoverViewNode} from "./components/hover/hover-view"; +import {defaultMarkdownConverter} from "./components/markdownConverter"; export class LanguageProvider { activeEditor: Ace.Editor | null; @@ -152,7 +152,7 @@ export class LanguageProvider { } }); - this.options.markdownConverter ||= new showdown.Converter(); + this.options.markdownConverter ||= defaultMarkdownConverter; if (options?.workspacePath) { this.workspaceUri = convertToUri(options.workspacePath); } diff --git a/tests/ui-smoke/ace-linters.contract.tests.ts b/tests/ui-smoke/ace-linters.contract.tests.ts index 12f3f7df..cde3968e 100644 --- a/tests/ui-smoke/ace-linters.contract.tests.ts +++ b/tests/ui-smoke/ace-linters.contract.tests.ts @@ -32,6 +32,18 @@ describe("ace-linters UI contract tests", function () { } }); + it("loads the UMD bundle in an AMD environment without runtime errors", async function () { + await harness.openScenario("ace-linters-amd"); + await harness.sleep(1500); + const page = harness.getPage(); + + const ready = await page.evaluate(() => window.testFlags.ready === true); + const errors = harness.getConsoleErrors(); + + expect(ready, "AMD scenario should finish booting").to.equal(true); + expect(errors, `Console errors: ${errors.join("\n")}`).to.be.empty; + }); + it("handles YAML schema options without critical runtime errors", async function () { await harness.openScenario("ace-linters"); await harness.initAceLinterFlags(); diff --git a/tests/ui-smoke/scenarios/ace-linters-amd.html b/tests/ui-smoke/scenarios/ace-linters-amd.html new file mode 100644 index 00000000..7179c065 --- /dev/null +++ b/tests/ui-smoke/scenarios/ace-linters-amd.html @@ -0,0 +1,43 @@ + + + + + ace-linters AMD smoke + + + +
+ + + + + + +