diff --git a/CHANGELOG.md b/CHANGELOG.md
index a296e52..73960e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.8.0] - 2023-10-05
+
+Updated [crossnote](https://github.com/shd101wyy/crossnote) to version [0.8.17](https://github.com/shd101wyy/crossnote/releases/tag/0.8.17) then version [0.8.18](https://github.com/shd101wyy/crossnote/releases/tag/0.8.18).
+
+### New features
+
+- 📝 Supported in-preview editor that allows you to edit the markdown file directly in the preview 🎉.
+ This feature is currently in beta.
+ When the editor is open, you can press `ctrl+s` or `cmd+s` to save the markdown file. You can also press `esc` to close the editor.
+- Deprecated the VS Code setting `markdown-preview-enhanced.singlePreview`.
+ Now replaced by `markdown-preview-enhanced.previewMode`:
+
+ - **Single Preview** (_default_)
+ Only one preview will be shown for all editors.
+ - **Multiple Previews**
+ Multiple previews will be shown. Each editor has its own preview.
+ - **Previews Only** 🆕
+ No editor will be shown. Only previews will be shown. You can use the in-preview editor to edit the markdown.
+
+ 🔔 Please note that enable this option will automatically modify the `workbench.editorAssociations` setting to make sure the markdown files are opened in the custom editor for preview.
+
+- Added two new VS Code commands `Markdown Preview Enhanced: Customize Preview Html Head (Workspace)` and `Markdown Preview Enhanced: Customize Preview Html Head (Global)`, which will open the `head.html` file for you to customize the `
` of the preview.
+
+- Supported to set attribute to image and link, e.g.:
+
+ ```markdown
+ ![](path/to/image.png){width=100 height=100}
+ ```
+
+- Improved the markdown transformer to better insert anchors for scroll sync and highlight lines and elements.
+ Added more tests for the markdown transformer to make sure it works as expected.
+- Added the reading time estimation in the preview footer ⏲️.
+- Added `Edit Markdown` menu item to the context menu of the preview, which offers two options:
+ - **Open VS Code Editor**
+ Open the markdown file in VS Code editor.
+ - **Open In-preview Editor**
+ Open the markdown file in the in-preview editor.
+- Updated the mermaid version to the latest `10.5.0`
+- Updated the `katex` version to `0.16.9`.
+- Added the API website: https://shd101wyy.github.io/crossnote/
+
+### Bug fixes
+
+- Fixed the font size of the `github-dark.css` code block theme.
+- Fixed the anchor jump bugs: https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/1790
+- Fixed list item style bug: https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/1789
+- Fixed a data race bug that caused the preview to hang.
+
## [0.7.10] - 2023-09-24
Updated [crossnote](https://github.com/shd101wyy/crossnote) to version [0.8.16](https://github.com/shd101wyy/crossnote/releases/tag/0.8.16)
diff --git a/build.js b/build.js
index 7a9e874..02d57a1 100644
--- a/build.js
+++ b/build.js
@@ -1,3 +1,4 @@
+const { execSync } = require('child_process');
const { context, build } = require('esbuild');
const { polyfillNode } = require('esbuild-plugin-polyfill-node');
@@ -10,6 +11,10 @@ const esbuildProblemMatcherPlugin = {
setup(build) {
build.onStart(() => {
console.log('[watch] build started');
+
+ // Run `gulp copy:files` before build
+ execSync('gulp copy-files');
+ console.log('[watch] gulp copy-files');
});
build.onEnd((result) => {
if (result.errors.length) {
@@ -18,7 +23,9 @@ const esbuildProblemMatcherPlugin = {
`> ${error.location.file}:${error.location.line}:${error.location.column}: error: ${error.text}`,
),
);
- } else console.log('[watch] build finished');
+ } else {
+ console.log('[watch] build finished');
+ }
});
},
};
diff --git a/package.json b/package.json
index 7c89630..0e76ebe 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "markdown-preview-enhanced",
"displayName": "%displayName%",
- "version": "0.7.10",
+ "version": "0.8.0",
"description": "%description%",
"categories": [
"Other"
@@ -23,11 +23,10 @@
"main": "./out/native/extension.js",
"browser": "./out/web/extension.js",
"scripts": {
- "build": "yarn copy:files && gulp clean-out && node build.js",
+ "build": "gulp copy-files && gulp clean-out && node build.js",
"check:all": "yarn check:eslint && yarn check:prettier",
"check:eslint": "eslint \"**/*\"",
"check:prettier": "prettier --check \"**/*.*\"",
- "copy:files": "gulp copy-files",
"fix:all": "yarn fix:eslint && yarn fix:eslint && yarn fix:prettier",
"fix:eslint": "eslint --fix \"**/*\"",
"fix:prettier": "prettier --write \"**/*.*\"",
@@ -36,7 +35,7 @@
"run-in-vscode-dev": "npx serve --cors -l 5000 --ssl-cert $HOME/certs/localhost.pem --ssl-key $HOME/certs/localhost-key.pem",
"test": "yarn build && node ./node_modules/vscode/bin/test",
"vscode:prepublish": "yarn install && yarn build",
- "watch": "yarn copy:files && gulp clean-out && node build.js --watch"
+ "watch": "gulp copy-files && gulp clean-out && node build.js --watch"
},
"contributes": {
"commands": [
@@ -122,6 +121,11 @@
"title": "%markdown-preview-enhanced.extendParser.title%",
"enablement": "!isWeb"
},
+ {
+ "command": "markdown-preview-enhanced.customizePreviewHtmlHead",
+ "title": "%markdown-preview-enhanced.customizePreviewHtmlHead.title%",
+ "enablement": "!isWeb"
+ },
{
"command": "markdown-preview-enhanced.openConfigScriptInWorkspace",
"title": "%markdown-preview-enhanced.openConfigScriptInWorkspace.title%"
@@ -130,6 +134,10 @@
"command": "markdown-preview-enhanced.extendParserInWorkspace",
"title": "%markdown-preview-enhanced.extendParserInWorkspace.title%"
},
+ {
+ "command": "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace",
+ "title": "%markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title%"
+ },
{
"command": "markdown-preview-enhanced.showUploadedImages",
"title": "%markdown-preview-enhanced.showUploadedImages.title%",
@@ -141,7 +149,7 @@
"title": "Markdown Preview Enhanced",
"properties": {
"markdown-preview-enhanced.configPath": {
- "markdownDescription": "Restart is required after changes. The configuration directory path. Leave it empty to use `$HOME/.crossnote` for Windows or `$XDG_CONFIG_HOME/.crossnote` or `$HOME/.local/state/crossnote` as the config path.",
+ "markdownDescription": "Restart is required after changes. The global configuration directory path. Leave it empty to use `$HOME/.crossnote` for Windows or `$XDG_CONFIG_HOME/.crossnote` or `$HOME/.local/state/crossnote` as the config path.",
"default": "",
"type": "string"
},
@@ -165,10 +173,15 @@
"default": true,
"type": "boolean"
},
- "markdown-preview-enhanced.singlePreview": {
- "description": "Open Only One Preview.",
- "default": true,
- "type": "boolean"
+ "markdown-preview-enhanced.previewMode": {
+ "markdownDescription": "- **Single Preview**: Only one preview will be shown for all editors.\n- **Multiple Previews**: Multiple previews will be shown. Each editor has its own preview.\n- **Previews Only**: No editor will be shown. Only previews will be shown. You can use the in-preview editor to edit the markdown.\n\nRestart is required after changes.",
+ "type": "string",
+ "enum": [
+ "Single Preview",
+ "Multiple Previews",
+ "Previews Only"
+ ],
+ "default": "Single Preview"
},
"markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited": {
"description": "Automatically show preview of markdown being edited.",
@@ -408,22 +421,22 @@
"qiniu"
]
},
- "markdown-preview-enhanced.AccessKey": {
+ "markdown-preview-enhanced.qiniuAccessKey": {
"type": "string",
"default": "",
"description": "Qiniu AccessKey"
},
- "markdown-preview-enhanced.SecretKey": {
+ "markdown-preview-enhanced.qiniuSecretKey": {
"type": "string",
"default": "",
"description": "Qiniu SecretKey"
},
- "markdown-preview-enhanced.Bucket": {
+ "markdown-preview-enhanced.qiniuBucket": {
"type": "string",
"default": "",
"description": "Qiniu Bucket"
},
- "markdown-preview-enhanced.Domain": {
+ "markdown-preview-enhanced.qiniuDomain": {
"type": "string",
"default": "http://",
"description": "Qiniu Domain"
@@ -556,6 +569,18 @@
}
}
},
+ "customEditors": [
+ {
+ "viewType": "markdown-preview-enhanced",
+ "displayName": "%customEditorPreviewDisplayName%",
+ "selector": [
+ {
+ "filenamePattern": "*.{md,markdown,mdown,mkdn,mkd,rmd,qmd}"
+ }
+ ],
+ "priority": "option"
+ }
+ ],
"keybindings": [
{
"command": "markdown-preview-enhanced.openPreviewToTheSide",
@@ -620,7 +645,8 @@
"dependencies": {
"@types/crypto-js": "^4.1.2",
"@types/vfile": "^3.0.2",
- "crossnote": "^0.8.16",
+ "async-mutex": "^0.4.0",
+ "crossnote": "^0.8.18",
"crypto-js": "^4.1.1"
},
"devDependencies": {
diff --git a/package.nls.json b/package.nls.json
index 66cc0e1..41f24b4 100644
--- a/package.nls.json
+++ b/package.nls.json
@@ -1,6 +1,7 @@
{
"displayName": "Markdown Preview Enhanced",
"description": "Markdown Preview Enhanced ported to vscode",
+ "customEditorPreviewDisplayName": "Markdown Preview Enhanced",
"markdown-preview-enhanced.openPreviewToTheSide.title": "Markdown Preview Enhanced: Open Preview to the Side",
"markdown-preview-enhanced.openPreview.title": "Markdown Preview Enhanced: Open Preview",
"markdown-preview-enhanced.toggleScrollSync.title": "Markdown Preview Enhanced: Toggle Scroll Sync",
@@ -20,5 +21,7 @@
"markdown-preview-enhanced.openConfigScriptInWorkspace.title": "Markdown Preview Enhanced: Open Config Script (Workspace)",
"markdown-preview-enhanced.extendParser.title": "Markdown Preview Enhanced: Extend Parser (Global)",
"markdown-preview-enhanced.extendParserInWorkspace.title": "Markdown Preview Enhanced: Extend Parser (Workspace)",
+ "markdown-preview-enhanced.customizePreviewHtmlHead.title": "Markdown Preview Enhanced: Customize Preview Html Head (Global)",
+ "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "Markdown Preview Enhanced: Customize Preview Html Head (Workspace)",
"markdown-preview-enhanced.showUploadedImages.title": "Markdown Preview Enhanced: Show Uploaded Images"
}
diff --git a/package.nls.zh.json b/package.nls.zh.json
index 20db3ac..b02a239 100644
--- a/package.nls.zh.json
+++ b/package.nls.zh.json
@@ -1,6 +1,7 @@
{
"displayName": "Markdown 增强预览",
"description": " 这款插件意在让你拥有飘逸的 Markdown 写作体验",
+ "customEditorPreviewDisplayName": "Markdown 增强预览",
"markdown-preview-enhanced.openPreviewToTheSide.title": "MPE:打开侧边预览",
"markdown-preview-enhanced.openPreview.title": "MPE:打开预览",
"markdown-preview-enhanced.toggleScrollSync.title": "MPE:开关预览滑动同步",
@@ -20,5 +21,7 @@
"markdown-preview-enhanced.openConfigScriptInWorkspace.title": "MPE:打开配置脚本(工作区)",
"markdown-preview-enhanced.extendParser.title": "MPE:扩展 Parser(全局)",
"markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:扩展 Parser(工作区)",
+ "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:自定义预览 HTML 头部(全局)",
+ "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:自定义预览 HTML 头部(工作区)",
"markdown-preview-enhanced.showUploadedImages.title": "MPE:显示图片上传历史"
}
diff --git a/prettier.config.js b/prettier.config.js
index 8148853..ddcacbd 100644
--- a/prettier.config.js
+++ b/prettier.config.js
@@ -1,9 +1,10 @@
/**@type {import("prettier").Config} */
module.exports = {
+ semi: true,
arrowParens: 'always',
endOfLine: 'lf',
quoteProps: 'consistent',
+ trailingComma: 'all',
singleQuote: true,
tabWidth: 2,
- trailingComma: 'all',
};
diff --git a/src/config.ts b/src/config.ts
index 4f7e120..4b620ea 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -2,14 +2,18 @@ import {
CodeBlockTheme,
FrontMatterRenderingOption,
ImageUploader,
+ KatexOptions,
MathRenderingOption,
+ MermaidConfig,
MermaidTheme,
NotebookConfig,
ParserConfig,
+ PreviewMode,
PreviewTheme,
RevealJsTheme,
getDefaultNotebookConfig,
} from 'crossnote';
+import { JsonObject } from 'type-fest';
import * as vscode from 'vscode';
import { isVSCodeWebExtension } from './utils';
@@ -19,6 +23,22 @@ export enum PreviewColorScheme {
editorColorScheme = 'editorColorScheme',
}
+type VSCodeMPEConfigKey =
+ | 'automaticallyShowPreviewOfMarkdownBeingEdited'
+ | 'configPath'
+ | 'imageUploader'
+ | 'hideDefaultVSCodeMarkdownPreviewButtons'
+ | 'liveUpdate'
+ | 'previewColorScheme'
+ | 'previewMode'
+ | 'qiniuAccessKey'
+ | 'qiniuBucket'
+ | 'qiniuDomain'
+ | 'qiniuSecretKey'
+ | 'scrollSync';
+
+type ConfigKey = keyof NotebookConfig | VSCodeMPEConfigKey;
+
export class MarkdownPreviewEnhancedConfig implements NotebookConfig {
public static getCurrentConfig() {
return new MarkdownPreviewEnhancedConfig();
@@ -47,7 +67,6 @@ export class MarkdownPreviewEnhancedConfig implements NotebookConfig {
public readonly revealjsTheme: RevealJsTheme;
public readonly protocolsWhiteList: string;
public readonly imageFolderPath: string;
- public readonly imageUploader: ImageUploader;
public readonly printBackground: boolean;
public readonly chromePath: string;
public readonly imageMagickPath: string;
@@ -66,162 +85,167 @@ export class MarkdownPreviewEnhancedConfig implements NotebookConfig {
public readonly puppeteerArgs: string[];
public readonly plantumlServer: string;
public readonly plantumlJarPath: string;
- public readonly hideDefaultVSCodeMarkdownPreviewButtons: boolean;
public readonly jsdelivrCdnHost: string;
public readonly krokiServer: string;
public readonly alwaysShowBacklinksInPreview: boolean;
+ // Don't set values for these properties in constructor:
+ public readonly includeInHeader: string;
+ public readonly globalCss: string;
+ public readonly mermaidConfig: MermaidConfig;
+ public readonly mathjaxConfig: JsonObject;
+ public readonly katexConfig: KatexOptions;
+ public readonly parserConfig: ParserConfig;
+ public readonly isVSCode: boolean = true;
// preview config
- public readonly scrollSync: boolean;
- public readonly liveUpdate: boolean;
- public readonly singlePreview: boolean;
public readonly automaticallyShowPreviewOfMarkdownBeingEdited: boolean;
+ public readonly hideDefaultVSCodeMarkdownPreviewButtons: boolean;
+ public readonly imageUploader: ImageUploader;
+ public readonly liveUpdate: boolean;
public readonly previewColorScheme: PreviewColorScheme;
+ public readonly previewMode: PreviewMode;
+ public readonly scrollSync: boolean;
private constructor() {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
const defaultConfig = getDefaultNotebookConfig();
this.markdownFileExtensions =
- config.get('markdownFileExtensions') ??
+ getMPEConfig('markdownFileExtensions') ??
defaultConfig.markdownFileExtensions;
- this.configPath = config.get('configPath') ?? '';
+ this.configPath = getMPEConfig('configPath') ?? '';
this.usePandocParser = isVSCodeWebExtension()
? false // pandoc is not supported in web extension
- : config.get('usePandocParser') ?? defaultConfig.usePandocParser;
+ : getMPEConfig('usePandocParser') ??
+ defaultConfig.usePandocParser;
this.breakOnSingleNewLine =
- config.get('breakOnSingleNewLine') ??
+ getMPEConfig('breakOnSingleNewLine') ??
defaultConfig.breakOnSingleNewLine;
this.enableTypographer =
- config.get('enableTypographer') ??
+ getMPEConfig('enableTypographer') ??
defaultConfig.enableTypographer;
this.enableWikiLinkSyntax =
- config.get('enableWikiLinkSyntax') ??
+ getMPEConfig('enableWikiLinkSyntax') ??
defaultConfig.enableWikiLinkSyntax;
this.enableLinkify =
- config.get('enableLinkify') ?? defaultConfig.enableLinkify;
+ getMPEConfig('enableLinkify') ?? defaultConfig.enableLinkify;
this.useGitHubStylePipedLink =
- config.get('useGitHubStylePipedLink') ??
+ getMPEConfig('useGitHubStylePipedLink') ??
defaultConfig.useGitHubStylePipedLink;
this.enableEmojiSyntax =
- config.get('enableEmojiSyntax') ??
+ getMPEConfig('enableEmojiSyntax') ??
defaultConfig.enableEmojiSyntax;
this.enableExtendedTableSyntax =
- config.get('enableExtendedTableSyntax') ??
+ getMPEConfig('enableExtendedTableSyntax') ??
defaultConfig.enableExtendedTableSyntax;
this.enableCriticMarkupSyntax =
- config.get('enableCriticMarkupSyntax') ??
+ getMPEConfig('enableCriticMarkupSyntax') ??
defaultConfig.enableCriticMarkupSyntax;
this.frontMatterRenderingOption =
- config.get('frontMatterRenderingOption') ??
+ getMPEConfig('frontMatterRenderingOption') ??
defaultConfig.frontMatterRenderingOption;
this.mermaidTheme =
- config.get('mermaidTheme') ?? defaultConfig.mermaidTheme;
+ getMPEConfig('mermaidTheme') ?? defaultConfig.mermaidTheme;
this.mathRenderingOption =
- (config.get('mathRenderingOption') as MathRenderingOption) ??
+ (getMPEConfig('mathRenderingOption') as MathRenderingOption) ??
defaultConfig.mathRenderingOption;
this.mathInlineDelimiters =
- config.get('mathInlineDelimiters') ??
+ getMPEConfig('mathInlineDelimiters') ??
defaultConfig.mathInlineDelimiters;
this.mathBlockDelimiters =
- config.get('mathBlockDelimiters') ??
+ getMPEConfig('mathBlockDelimiters') ??
defaultConfig.mathBlockDelimiters;
this.mathRenderingOnlineService =
- config.get('mathRenderingOnlineService') ??
+ getMPEConfig('mathRenderingOnlineService') ??
defaultConfig.mathRenderingOnlineService;
this.mathjaxV3ScriptSrc =
- config.get('mathjaxV3ScriptSrc') ??
+ getMPEConfig('mathjaxV3ScriptSrc') ??
defaultConfig.mathjaxV3ScriptSrc;
this.codeBlockTheme =
- config.get('codeBlockTheme') ??
+ getMPEConfig('codeBlockTheme') ??
defaultConfig.codeBlockTheme;
this.previewTheme =
- config.get('previewTheme') ?? defaultConfig.previewTheme;
+ getMPEConfig('previewTheme') ?? defaultConfig.previewTheme;
this.revealjsTheme =
- config.get('revealjsTheme') ?? defaultConfig.revealjsTheme;
+ getMPEConfig('revealjsTheme') ??
+ defaultConfig.revealjsTheme;
this.protocolsWhiteList =
- config.get('protocolsWhiteList') ??
+ getMPEConfig('protocolsWhiteList') ??
defaultConfig.protocolsWhiteList;
this.imageFolderPath =
- config.get('imageFolderPath') ?? defaultConfig.imageFolderPath;
- this.imageUploader = config.get('imageUploader') ?? 'imgur';
+ getMPEConfig('imageFolderPath') ?? defaultConfig.imageFolderPath;
+ this.imageUploader =
+ getMPEConfig('imageUploader') ?? 'imgur';
this.printBackground =
- config.get('printBackground') ?? defaultConfig.printBackground;
+ getMPEConfig('printBackground') ?? defaultConfig.printBackground;
this.chromePath =
- config.get('chromePath') ?? defaultConfig.chromePath;
+ getMPEConfig('chromePath') ?? defaultConfig.chromePath;
this.imageMagickPath =
- config.get('imageMagickPath') ?? defaultConfig.imageMagickPath;
+ getMPEConfig('imageMagickPath') ?? defaultConfig.imageMagickPath;
this.pandocPath =
- config.get('pandocPath') ?? defaultConfig.pandocPath;
+ getMPEConfig('pandocPath') ?? defaultConfig.pandocPath;
this.pandocMarkdownFlavor =
- config.get('pandocMarkdownFlavor') ??
+ getMPEConfig('pandocMarkdownFlavor') ??
defaultConfig.pandocMarkdownFlavor;
this.pandocArguments =
- config.get('pandocArguments') ?? defaultConfig.pandocArguments;
+ getMPEConfig('pandocArguments') ??
+ defaultConfig.pandocArguments;
this.latexEngine =
- config.get('latexEngine') ?? defaultConfig.latexEngine;
+ getMPEConfig('latexEngine') ?? defaultConfig.latexEngine;
this.enableScriptExecution =
- config.get('enableScriptExecution') ??
+ getMPEConfig('enableScriptExecution') ??
defaultConfig.enableScriptExecution;
- this.scrollSync = config.get('scrollSync') ?? true;
- this.liveUpdate = config.get('liveUpdate') ?? true;
- this.singlePreview = config.get('singlePreview') ?? true;
+ this.scrollSync = getMPEConfig('scrollSync') ?? true;
+ this.liveUpdate = getMPEConfig('liveUpdate') ?? true;
+ this.previewMode =
+ getMPEConfig('previewMode') ?? PreviewMode.SinglePreview;
this.automaticallyShowPreviewOfMarkdownBeingEdited =
- config.get('automaticallyShowPreviewOfMarkdownBeingEdited') ??
+ getMPEConfig('automaticallyShowPreviewOfMarkdownBeingEdited') ??
false;
this.previewColorScheme =
- config.get('previewColorScheme') ??
+ getMPEConfig('previewColorScheme') ??
PreviewColorScheme.selectedPreviewTheme;
this.enableHTML5Embed =
- config.get('enableHTML5Embed') ?? defaultConfig.enableHTML5Embed;
+ getMPEConfig('enableHTML5Embed') ??
+ defaultConfig.enableHTML5Embed;
this.HTML5EmbedUseImageSyntax =
- config.get('HTML5EmbedUseImageSyntax') ??
+ getMPEConfig('HTML5EmbedUseImageSyntax') ??
defaultConfig.HTML5EmbedUseImageSyntax;
this.HTML5EmbedUseLinkSyntax =
- config.get('HTML5EmbedUseLinkSyntax') ??
+ getMPEConfig('HTML5EmbedUseLinkSyntax') ??
defaultConfig.HTML5EmbedUseLinkSyntax;
this.HTML5EmbedIsAllowedHttp =
- config.get('HTML5EmbedIsAllowedHttp') ??
+ getMPEConfig('HTML5EmbedIsAllowedHttp') ??
defaultConfig.HTML5EmbedIsAllowedHttp;
this.HTML5EmbedAudioAttributes =
- config.get('HTML5EmbedAudioAttributes') ??
+ getMPEConfig('HTML5EmbedAudioAttributes') ??
defaultConfig.HTML5EmbedAudioAttributes;
this.HTML5EmbedVideoAttributes =
- config.get('HTML5EmbedVideoAttributes') ??
+ getMPEConfig('HTML5EmbedVideoAttributes') ??
defaultConfig.HTML5EmbedVideoAttributes;
this.puppeteerWaitForTimeout =
- config.get('puppeteerWaitForTimeout') ??
+ getMPEConfig('puppeteerWaitForTimeout') ??
defaultConfig.puppeteerWaitForTimeout;
this.puppeteerArgs =
- config.get('puppeteerArgs') ?? defaultConfig.puppeteerArgs;
+ getMPEConfig('puppeteerArgs') ?? defaultConfig.puppeteerArgs;
this.plantumlJarPath =
- config.get('plantumlJarPath') ?? defaultConfig.plantumlJarPath;
+ getMPEConfig('plantumlJarPath') ?? defaultConfig.plantumlJarPath;
this.plantumlServer =
- config.get('plantumlServer') ?? defaultConfig.plantumlServer;
+ getMPEConfig('plantumlServer') ?? defaultConfig.plantumlServer;
if (!this.plantumlServer && isVSCodeWebExtension()) {
this.plantumlServer = 'https://kroki.io/plantuml/svg/';
}
this.hideDefaultVSCodeMarkdownPreviewButtons =
- config.get('hideDefaultVSCodeMarkdownPreviewButtons') ?? true;
+ getMPEConfig('hideDefaultVSCodeMarkdownPreviewButtons') ?? true;
this.jsdelivrCdnHost =
- config.get('jsdelivrCdnHost') ?? defaultConfig.jsdelivrCdnHost;
+ getMPEConfig('jsdelivrCdnHost') ?? defaultConfig.jsdelivrCdnHost;
this.krokiServer =
- config.get('krokiServer') ?? defaultConfig.krokiServer;
+ getMPEConfig('krokiServer') ?? defaultConfig.krokiServer;
this.alwaysShowBacklinksInPreview =
- config.get('alwaysShowBacklinksInPreview') ??
+ getMPEConfig('alwaysShowBacklinksInPreview') ??
defaultConfig.alwaysShowBacklinksInPreview;
}
- globalCss: string;
- mermaidConfig;
- mathjaxConfig;
- katexConfig;
- parserConfig: ParserConfig;
- isVSCode: boolean;
-
public isEqualTo(otherConfig: MarkdownPreviewEnhancedConfig) {
const json1 = JSON.stringify(this);
const json2 = JSON.stringify(otherConfig);
@@ -230,3 +254,18 @@ export class MarkdownPreviewEnhancedConfig implements NotebookConfig {
[key: string]: any;
}
+
+export function getMPEConfig(section: ConfigKey) {
+ const config = vscode.workspace.getConfiguration('markdown-preview-enhanced');
+ return config.get(section);
+}
+
+export function updateMPEConfig(
+ section: ConfigKey,
+ value: T,
+ configurationTarget?: boolean | vscode.ConfigurationTarget | null | undefined,
+ overrideInLanguage?: boolean | undefined,
+) {
+ const config = vscode.workspace.getConfiguration('markdown-preview-enhanced');
+ return config.update(section, value, configurationTarget, overrideInLanguage);
+}
diff --git a/src/extension-common.ts b/src/extension-common.ts
index 47485de..7df4819 100644
--- a/src/extension-common.ts
+++ b/src/extension-common.ts
@@ -1,13 +1,16 @@
// For both node.js and browser environments
-import { utility } from 'crossnote';
+import { PreviewMode, utility } from 'crossnote';
import { SHA256 } from 'crypto-js';
import * as vscode from 'vscode';
-import { PreviewColorScheme } from './config';
+import { PreviewColorScheme, getMPEConfig, updateMPEConfig } from './config';
import { pasteImageFile, uploadImageFile } from './image-helper';
import NotebooksManager from './notebooks-manager';
+import { PreviewCustomEditorProvider } from './preview-custom-editor-provider';
import { PreviewProvider, getPreviewUri } from './preview-provider';
import {
getBottomVisibleLine,
+ getEditorActiveLine,
+ getPreviewMode,
getTopVisibleLine,
getWorkspaceFolderUri,
isMarkdownFile,
@@ -28,8 +31,9 @@ if (hideDefaultVSCodeMarkdownPreviewButtons) {
);
}
-export function initExtensionCommon(context: vscode.ExtensionContext) {
+export async function initExtensionCommon(context: vscode.ExtensionContext) {
const notebooksManager = new NotebooksManager(context);
+ await notebooksManager.updateWorkbenchEditorAssociationsBasedOnPreviewMode();
PreviewProvider.notebooksManager = notebooksManager;
function getCurrentWorkingDirectory() {
@@ -57,9 +61,14 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
}
const previewProvider = await getPreviewContentProvider(uri);
- previewProvider.initPreview(uri, editor, {
- viewColumn: vscode.ViewColumn.Two,
- preserveFocus: true,
+ previewProvider.initPreview({
+ sourceUri: uri,
+ document: editor.document,
+ activeLine: getEditorActiveLine(editor),
+ viewOptions: {
+ viewColumn: vscode.ViewColumn.Two,
+ preserveFocus: true,
+ },
});
}
@@ -73,61 +82,49 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
}
const previewProvider = await getPreviewContentProvider(uri);
- previewProvider.initPreview(uri, editor, {
- viewColumn: vscode.ViewColumn.One,
- preserveFocus: false,
+ previewProvider.initPreview({
+ sourceUri: uri,
+ document: editor.document,
+ activeLine: getEditorActiveLine(editor),
+ viewOptions: {
+ viewColumn: vscode.ViewColumn.One,
+ preserveFocus: false,
+ },
});
}
- function toggleScrollSync() {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- const scrollSync = !config.get('scrollSync');
- config.update('scrollSync', scrollSync, true).then(() => {
- notebooksManager.updateConfiguration();
- if (scrollSync) {
- vscode.window.showInformationMessage('Scroll Sync is enabled');
- } else {
- vscode.window.showInformationMessage('Scroll Sync is disabled');
- }
- });
+ async function toggleScrollSync() {
+ const scrollSync = !getMPEConfig('scrollSync');
+ await updateMPEConfig('scrollSync', scrollSync, true);
+ if (scrollSync) {
+ vscode.window.showInformationMessage('Scroll Sync is enabled');
+ } else {
+ vscode.window.showInformationMessage('Scroll Sync is disabled');
+ }
}
- function toggleLiveUpdate() {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- const liveUpdate = !config.get('liveUpdate');
- config.update('liveUpdate', liveUpdate, true).then(() => {
- notebooksManager.updateConfiguration();
- if (liveUpdate) {
- vscode.window.showInformationMessage('Live Update is enabled');
- } else {
- vscode.window.showInformationMessage('Live Update is disabled');
- }
- });
+ async function toggleLiveUpdate() {
+ const liveUpdate = !getMPEConfig('liveUpdate');
+ await updateMPEConfig('liveUpdate', liveUpdate, true);
+ if (liveUpdate) {
+ vscode.window.showInformationMessage('Live Update is enabled');
+ } else {
+ vscode.window.showInformationMessage('Live Update is disabled');
+ }
}
- function toggleBreakOnSingleNewLine() {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- const breakOnSingleNewLine = !config.get('breakOnSingleNewLine');
- config
- .update('breakOnSingleNewLine', breakOnSingleNewLine, true)
- .then(() => {
- notebooksManager.updateConfiguration();
- if (breakOnSingleNewLine) {
- vscode.window.showInformationMessage(
- 'Break On Single New Line is enabled',
- );
- } else {
- vscode.window.showInformationMessage(
- 'Break On Single New Line is disabled',
- );
- }
- });
+ async function toggleBreakOnSingleNewLine() {
+ const breakOnSingleNewLine = !getMPEConfig('breakOnSingleNewLine');
+ updateMPEConfig('breakOnSingleNewLine', breakOnSingleNewLine, true);
+ if (breakOnSingleNewLine) {
+ vscode.window.showInformationMessage(
+ 'Break On Single New Line is enabled',
+ );
+ } else {
+ vscode.window.showInformationMessage(
+ 'Break On Single New Line is disabled',
+ );
+ }
}
function insertNewSlide() {
@@ -382,31 +379,19 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
}
function setPreviewTheme(uri, theme) {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- config.update('previewTheme', theme, true);
+ updateMPEConfig('previewTheme', theme, true);
}
function setCodeBlockTheme(uri, theme) {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- config.update('codeBlockTheme', theme, true);
+ updateMPEConfig('codeBlockTheme', theme, true);
}
function setRevealjsTheme(uri, theme) {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- config.update('revealjsTheme', theme, true);
+ updateMPEConfig('revealjsTheme', theme, true);
}
function setImageUploader(imageUploader) {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- config.update('imageUploader', imageUploader, true);
+ updateMPEConfig('imageUploader', imageUploader, true);
}
function openConfigFileInWorkspace(
@@ -418,11 +403,7 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
vscode.commands.executeCommand('vscode.open', filePath);
},
async () => {
- const provider = await getPreviewContentProvider(workspaceUri);
- await provider.updateCrossnoteConfig(
- path.join(workspaceUri.fsPath, '.crossnote'),
- true,
- );
+ await notebooksManager.updateNotebookConfig(workspaceUri, true);
vscode.commands.executeCommand('vscode.open', filePath);
},
);
@@ -475,6 +456,22 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
openConfigFileInWorkspace(currentWorkingDirectory, parserConfigPath);
}
+ function customizePreviewHtmlHeadInWorkspace() {
+ const currentWorkingDirectory = getCurrentWorkingDirectory();
+ if (!currentWorkingDirectory) {
+ return vscode.window.showErrorMessage(
+ 'Please open a folder before customizing preview html head',
+ );
+ }
+
+ const headHtmlPath = vscode.Uri.joinPath(
+ currentWorkingDirectory,
+ './.crossnote/head.html',
+ );
+
+ openConfigFileInWorkspace(currentWorkingDirectory, headHtmlPath);
+ }
+
async function clickTagA({
uri,
href,
@@ -541,9 +538,8 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
}
}
- // open file if needed, if not we will use already opened editor
+ // open file if needed, if not we will use already opened editor
// (by specifying view column in which it is already shown)
-
let fileExists = false;
try {
fileExists = !!(await vscode.workspace.fs.stat(fileUri));
@@ -552,21 +548,51 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
}
if (fileExists) {
- // Open fileUri
- vscode.workspace.openTextDocument(fileUri).then((doc) => {
- vscode.window.showTextDocument(doc, col).then((editor) => {
- // if there was line fragment, jump to line
- if (line >= 0) {
- let viewPos = vscode.TextEditorRevealType.InCenter;
- if (editor.selection.active.line === line) {
- viewPos = vscode.TextEditorRevealType.InCenterIfOutsideViewport;
- }
- const sel = new vscode.Selection(line, 0, line, 0);
- editor.selection = sel;
- editor.revealRange(sel, viewPos);
- }
+ const previewMode = getPreviewMode();
+ const document = await vscode.workspace.openTextDocument(fileUri);
+ // Open custom editor
+ if (
+ previewMode === PreviewMode.PreviewsOnly &&
+ isMarkdownFile(document)
+ ) {
+ /*
+ // NOTE: This doesn't work for the `line`
+ // so we use the `initPreview` instead.
+ const options: vscode.TextDocumentShowOptions = {
+ selection: new vscode.Selection(line, 0, line, 0),
+ viewColumn: vscode.ViewColumn.Active,
+ };
+ vscode.commands.executeCommand(
+ 'vscode.openWith',
+ fileUri,
+ 'markdown-preview-enhanced',
+ options,
+ );
+ */
+ const previewProvider = await getPreviewContentProvider(fileUri);
+ previewProvider.initPreview({
+ sourceUri: fileUri,
+ document,
+ activeLine: line,
+ viewOptions: {
+ viewColumn: vscode.ViewColumn.Active,
+ preserveFocus: true,
+ },
});
- });
+ } else {
+ // Open fileUri
+ const editor = await vscode.window.showTextDocument(document, col);
+ // if there was line fragment, jump to line
+ if (line >= 0) {
+ let viewPos = vscode.TextEditorRevealType.InCenter;
+ if (editor.selection.active.line === line) {
+ viewPos = vscode.TextEditorRevealType.InCenterIfOutsideViewport;
+ }
+ const sel = new vscode.Selection(line, 0, line, 0);
+ editor.selection = sel;
+ editor.revealRange(sel, viewPos);
+ }
+ }
} else {
vscode.commands.executeCommand(
'vscode.open',
@@ -603,6 +629,15 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(url));
}
+ async function openExternalEditor(uri: string) {
+ const sourceUri = vscode.Uri.parse(uri);
+ const document = await vscode.workspace.openTextDocument(sourceUri);
+ await vscode.window.showTextDocument(document, {
+ preview: false,
+ viewColumn: vscode.ViewColumn.Active,
+ });
+ }
+
async function showBacklinks({
uri,
forceRefreshingNotes,
@@ -627,11 +662,22 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
});
}
+ async function updateMarkdown(uri: string, markdown: string) {
+ try {
+ const sourceUri = vscode.Uri.parse(uri);
+ // Write markdown to file
+ await vscode.workspace.fs.writeFile(sourceUri, Buffer.from(markdown));
+ // Update preview
+ const previewProvider = await getPreviewContentProvider(sourceUri);
+ previewProvider.updateMarkdown(sourceUri);
+ } catch (error) {
+ vscode.window.showErrorMessage(error);
+ console.error(error);
+ }
+ }
+
async function toggleAlwaysShowBacklinksInPreview(uri, flag) {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- config.update('alwaysShowBacklinksInPreview', flag, true);
+ updateMPEConfig('alwaysShowBacklinksInPreview', flag, true);
}
context.subscriptions.push(
@@ -657,9 +703,7 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
)
) {
const provider = await getPreviewContentProvider(document.uri);
- await provider.updateCrossnoteConfig(
- path.join(workspaceDir, '.crossnote'),
- );
+ await notebooksManager.updateNotebookConfig(workspaceUri);
provider.refreshAllPreviews();
}
}
@@ -678,14 +722,25 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
);
context.subscriptions.push(
- vscode.workspace.onDidChangeConfiguration(() => {
- notebooksManager.updateConfiguration();
+ vscode.workspace.onDidChangeConfiguration((event) => {
+ // console.log(
+ // 'onDidChangeConfiguration: ',
+ // event.affectsConfiguration('markdown-preview-enhanced'),
+ // );
+ if (event.affectsConfiguration('markdown-preview-enhanced')) {
+ notebooksManager.updateAllNotebooksConfig();
+ }
}),
);
context.subscriptions.push(
vscode.window.onDidChangeTextEditorSelection(async (event) => {
if (isMarkdownFile(event.textEditor.document)) {
+ const previewMode = getPreviewMode();
+ if (previewMode === PreviewMode.PreviewsOnly) {
+ return;
+ }
+
const firstVisibleScreenRow = getTopVisibleLine(event.textEditor);
const lastVisibleScreenRow = getBottomVisibleLine(event.textEditor);
@@ -756,20 +811,16 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
/**
* Open preview automatically if the `automaticallyShowPreviewOfMarkdownBeingEdited` is on.
- * @param textEditor
*/
context.subscriptions.push(
- vscode.window.onDidChangeActiveTextEditor(async (textEditor) => {
- if (textEditor && textEditor.document && textEditor.document.uri) {
- if (isMarkdownFile(textEditor.document)) {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- const sourceUri = textEditor.document.uri;
- const automaticallyShowPreviewOfMarkdownBeingEdited = config.get<
+ vscode.window.onDidChangeActiveTextEditor(async (editor) => {
+ if (editor && editor.document && editor.document.uri) {
+ if (isMarkdownFile(editor.document)) {
+ const sourceUri = editor.document.uri;
+ const automaticallyShowPreviewOfMarkdownBeingEdited = getMPEConfig<
boolean
>('automaticallyShowPreviewOfMarkdownBeingEdited');
- const isUsingSinglePreview = config.get('singlePreview');
+ const previewMode = getPreviewMode();
/**
* Is using single preview and the preview is on.
* When we switched text ed()tor, update preview to that text editor.
@@ -777,21 +828,27 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
const previewProvider = await getPreviewContentProvider(sourceUri);
if (previewProvider.isPreviewOn(sourceUri)) {
if (
- isUsingSinglePreview &&
+ previewMode === PreviewMode.SinglePreview &&
!previewProvider.previewHasTheSameSingleSourceUri(sourceUri)
) {
- previewProvider.initPreview(sourceUri, textEditor, {
- viewColumn:
- previewProvider.getPreview(sourceUri)?.viewColumn ??
- vscode.ViewColumn.One,
- preserveFocus: true,
+ previewProvider.initPreview({
+ sourceUri,
+ document: editor.document,
+ activeLine: getEditorActiveLine(editor),
+ viewOptions: {
+ viewColumn:
+ previewProvider.getPreviews(sourceUri)?.at(0)?.viewColumn ??
+ vscode.ViewColumn.One,
+ preserveFocus: true,
+ },
});
- } else if (!isUsingSinglePreview) {
- const previewPanel = previewProvider.getPreview(sourceUri);
- if (previewPanel) {
- previewPanel.reveal(/*vscode.ViewColumn.Two*/ undefined, true);
+ } else if (previewMode === PreviewMode.MultiplePreviews) {
+ const previews = previewProvider.getPreviews(sourceUri);
+ if (previews && previews.length > 0) {
+ previews[0].reveal(/*vscode.ViewColumn.Two*/ undefined, true);
}
}
+ // NOTE: For PreviewMode.PreviewsOnly, we don't need to do anything.
} else if (automaticallyShowPreviewOfMarkdownBeingEdited) {
openPreviewToTheSide(sourceUri);
}
@@ -803,23 +860,22 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
// Changed editor color theme
context.subscriptions.push(
vscode.window.onDidChangeActiveColorTheme((theme) => {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
if (
- config.get('previewColorScheme') ===
+ getMPEConfig('previewColorScheme') ===
PreviewColorScheme.editorColorScheme
) {
- notebooksManager.updateConfiguration();
+ notebooksManager.updateAllNotebooksConfig();
}
}),
);
/*
- context.subscriptions.push(vscode.workspace.onDidOpenTextDocument((textDocument)=> {
- // console.log('onDidOpenTextDocument', textDocument.uri)
- }))
- */
+ context.subscriptions.push(
+ vscode.workspace.onDidOpenTextDocument((document) => {
+ // console.log('onDidOpenTextDocument: ', document.uri.fsPath);
+ }),
+ );
+ */
/*
context.subscriptions.push(vscode.window.onDidChangeVisibleTextEditors(textEditors=> {
@@ -1060,6 +1116,13 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('_crossnote.openSponsors', openSponsors),
);
+ context.subscriptions.push(
+ vscode.commands.registerCommand(
+ '_crossnote.openExternalEditor',
+ openExternalEditor,
+ ),
+ );
+
context.subscriptions.push(
vscode.commands.registerCommand(
'markdown-preview-enhanced.customizeCssInWorkspace',
@@ -1081,6 +1144,13 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
),
);
+ context.subscriptions.push(
+ vscode.commands.registerCommand(
+ 'markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace',
+ customizePreviewHtmlHeadInWorkspace,
+ ),
+ );
+
context.subscriptions.push(
vscode.commands.registerCommand('_crossnote.clickTagA', clickTagA),
);
@@ -1089,12 +1159,26 @@ export function initExtensionCommon(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('_crossnote.showBacklinks', showBacklinks),
);
+ context.subscriptions.push(
+ vscode.commands.registerCommand(
+ '_crossnote.updateMarkdown',
+ updateMarkdown,
+ ),
+ );
+
context.subscriptions.push(
vscode.commands.registerCommand(
'_crossnote.toggleAlwaysShowBacklinksInPreview',
toggleAlwaysShowBacklinksInPreview,
),
);
+
+ context.subscriptions.push(
+ vscode.window.registerCustomEditorProvider(
+ 'markdown-preview-enhanced',
+ new PreviewCustomEditorProvider(context),
+ ),
+ );
}
function revealLine(uri, line) {
diff --git a/src/extension-web.ts b/src/extension-web.ts
index 8b5c5e8..3fca217 100644
--- a/src/extension-web.ts
+++ b/src/extension-web.ts
@@ -1,9 +1,9 @@
import * as vscode from 'vscode';
import { initExtensionCommon } from './extension-common';
-export function activate(context: vscode.ExtensionContext) {
+export async function activate(context: vscode.ExtensionContext) {
// Init the extension-common module
- initExtensionCommon(context);
+ await initExtensionCommon(context);
}
// This method is called when your extension is deactivated
export function deactivate() {}
diff --git a/src/extension.ts b/src/extension.ts
index e3e1046..76f2f55 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -5,12 +5,12 @@ import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { initExtensionCommon } from './extension-common';
-import { getAllPreviewProviders } from './preview-provider';
+import { PreviewProvider } from './preview-provider';
import { globalConfigPath } from './utils';
-// this method is called when your extension iopenTextDocuments activated
+// this method is called when your extension openTextDocuments activated
// your extension is activated the very first time the command is executed
-export function activate(context: vscode.ExtensionContext) {
+export async function activate(context: vscode.ExtensionContext) {
try {
if (!fs.existsSync(globalConfigPath)) {
fs.mkdirSync(globalConfigPath, { recursive: true });
@@ -23,11 +23,7 @@ export function activate(context: vscode.ExtensionContext) {
fileName ?? '',
)
) {
- const providers = getAllPreviewProviders();
- providers.forEach(async (provider) => {
- await provider.updateCrossnoteConfig(globalConfigPath);
- provider.refreshAllPreviews();
- });
+ PreviewProvider.notebooksManager?.updateAllNotebooksConfig();
}
});
} catch (error) {
@@ -35,7 +31,7 @@ export function activate(context: vscode.ExtensionContext) {
}
// Init the extension-common module
- initExtensionCommon(context);
+ await initExtensionCommon(context);
function customizeCSS() {
const globalStyleLessFile = utility.addFileProtocol(
@@ -67,6 +63,16 @@ export function activate(context: vscode.ExtensionContext) {
);
}
+ function customizePreviewHtmlHead() {
+ const headHtmlPath = utility.addFileProtocol(
+ path.resolve(globalConfigPath, './head.html'),
+ );
+ vscode.commands.executeCommand(
+ 'vscode.open',
+ vscode.Uri.parse(headHtmlPath),
+ );
+ }
+
function showUploadedImages() {
const imageHistoryFilePath = utility.addFileProtocol(
path.resolve(globalConfigPath, './image_history.md'),
@@ -98,6 +104,13 @@ export function activate(context: vscode.ExtensionContext) {
),
);
+ context.subscriptions.push(
+ vscode.commands.registerCommand(
+ 'markdown-preview-enhanced.customizePreviewHtmlHead',
+ customizePreviewHtmlHead,
+ ),
+ );
+
context.subscriptions.push(
vscode.commands.registerCommand(
'markdown-preview-enhanced.showUploadedImages',
@@ -106,7 +119,6 @@ export function activate(context: vscode.ExtensionContext) {
);
// context.subscriptions.push(vscode.commands.registerCommand('_crossnote.cacheSVG', cacheSVG))
-
context.subscriptions.push(
vscode.commands.registerCommand(
'_crossnote.showUploadedImageHistory',
diff --git a/src/file-watcher.ts b/src/file-watcher.ts
index 553c385..2556b85 100644
--- a/src/file-watcher.ts
+++ b/src/file-watcher.ts
@@ -1,4 +1,5 @@
import * as vscode from 'vscode';
+import { getMPEConfig } from './config';
import NotebooksManager from './notebooks-manager';
import { getAllPreviewProviders } from './preview-provider';
@@ -14,11 +15,8 @@ export default class FileWatcher {
return;
}
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
const markdownFileExtensions =
- config.get('markdownFileExtensions') ?? [];
+ getMPEConfig('markdownFileExtensions') ?? [];
const glob: string = `**/*.{${markdownFileExtensions
.map((ext) => ext.replace(/^\./, ''))
.join(',')}}`;
diff --git a/src/image-helper.ts b/src/image-helper.ts
index 5143644..58f544c 100644
--- a/src/image-helper.ts
+++ b/src/image-helper.ts
@@ -2,6 +2,7 @@ import { utility } from 'crossnote';
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
+import { getMPEConfig } from './config';
import { getWorkspaceFolderUri, isMarkdownFile } from './utils';
/**
@@ -197,13 +198,10 @@ export function uploadImageFile(
textEditorEdit.insert(curPos, hint);
});
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
- const AccessKey = config.get('AccessKey') || '';
- const SecretKey = config.get('SecretKey') || '';
- const Bucket = config.get('Bucket') || '';
- const Domain = config.get('Domain') || '';
+ const AccessKey = getMPEConfig('qiniuAccessKey') || '';
+ const SecretKey = getMPEConfig('qiniuSecretKey') || '';
+ const Bucket = getMPEConfig('qiniuBucket') || '';
+ const Domain = getMPEConfig('qiniuDomain') || '';
utility
.uploadImage(imageFilePath, {
diff --git a/src/notebooks-manager.ts b/src/notebooks-manager.ts
index 99ebe9d..4b15095 100644
--- a/src/notebooks-manager.ts
+++ b/src/notebooks-manager.ts
@@ -1,6 +1,16 @@
-import { Notebook, PreviewTheme, loadConfigsInDirectory } from 'crossnote';
+import {
+ Notebook,
+ NotebookConfig,
+ PreviewMode,
+ PreviewTheme,
+ loadConfigsInDirectory,
+} from 'crossnote';
import * as vscode from 'vscode';
-import { MarkdownPreviewEnhancedConfig, PreviewColorScheme } from './config';
+import {
+ MarkdownPreviewEnhancedConfig,
+ PreviewColorScheme,
+ getMPEConfig,
+} from './config';
import FileWatcher from './file-watcher';
import { getAllPreviewProviders } from './preview-provider';
import {
@@ -12,12 +22,11 @@ import { wrapVSCodeFSAsApi } from './vscode-fs';
class NotebooksManager {
private notebooks: Notebook[] = [];
- public config: MarkdownPreviewEnhancedConfig;
public systemColorScheme: 'light' | 'dark' = 'light';
private fileWatcher: FileWatcher;
+ private currentMPEConfig: MarkdownPreviewEnhancedConfig = MarkdownPreviewEnhancedConfig.getCurrentConfig();
constructor(private context: vscode.ExtensionContext) {
- this.config = MarkdownPreviewEnhancedConfig.getCurrentConfig();
this.fileWatcher = new FileWatcher(this.context, this);
}
@@ -34,75 +43,159 @@ class NotebooksManager {
const notebook = await Notebook.init({
notebookPath: workspaceFolderUri.toString(),
fs: wrapVSCodeFSAsApi(workspaceFolderUri.scheme),
- config: { ...this.config },
+ config: {},
});
this.notebooks.push(notebook);
+ notebook.updateConfig(await this.loadNotebookConfig(uri));
+ return notebook;
+ }
- // Check if ${workspaceDir}/.crossnote directory exists
- // If not, then use the global config.
- const crossnoteDir = vscode.Uri.joinPath(
- workspaceFolderUri,
- './.crossnote',
+ public async updateNotebookConfig(
+ uri: vscode.Uri,
+ createWorkspaceConfigDirectoryIfNotExists: boolean = false,
+ ) {
+ const notebook = await this.getNotebook(uri);
+ const config = await this.loadNotebookConfig(
+ uri,
+ createWorkspaceConfigDirectoryIfNotExists,
);
- if (
- !(await notebook.fs.exists(crossnoteDir.fsPath)) &&
- !isVSCodeWebExtension()
- ) {
+ notebook.updateConfig(config);
+ }
+
+ private async loadNotebookConfig(
+ uri: vscode.Uri,
+ createWorkspaceConfigDirectoryIfNotExists: boolean = false,
+ ): Promise> {
+ const notebook = await this.getNotebook(uri);
+
+ // Global config
+ let globalConfig: Partial = {};
+ if (!isVSCodeWebExtension()) {
try {
- const globalConfig = await loadConfigsInDirectory(
+ globalConfig = await loadConfigsInDirectory(
globalConfigPath,
notebook.fs,
true,
);
- notebook.updateConfig(globalConfig);
} catch (error) {
console.error(error);
}
}
- return notebook;
+ // Workspace config
+ let workspaceConfig: Partial = {};
+ const workspaceConfigPath = vscode.Uri.joinPath(
+ getWorkspaceFolderUri(uri),
+ './.crossnote',
+ );
+ try {
+ workspaceConfig = await loadConfigsInDirectory(
+ workspaceConfigPath.fsPath,
+ notebook.fs,
+ createWorkspaceConfigDirectoryIfNotExists,
+ );
+ } catch (error) {
+ console.error(error);
+ }
+
+ // VSCode config
+ const vscodeMPEConfig = MarkdownPreviewEnhancedConfig.getCurrentConfig();
+ this.currentMPEConfig = vscodeMPEConfig;
+
+ // Preview theme
+ const previewTheme = this.getPreviewTheme(
+ vscodeMPEConfig.previewTheme,
+ vscodeMPEConfig.previewColorScheme,
+ );
+
+ return {
+ ...vscodeMPEConfig,
+ ...globalConfig,
+ ...workspaceConfig,
+ previewTheme,
+ };
}
public setSystemColorScheme(colorScheme: 'light' | 'dark') {
if (this.systemColorScheme !== colorScheme) {
this.systemColorScheme = colorScheme;
if (
- this.config.previewColorScheme === PreviewColorScheme.systemColorScheme
+ getMPEConfig('previewColorScheme') ===
+ PreviewColorScheme.systemColorScheme
) {
- this.updateConfiguration(true);
+ this.updateAllNotebooksConfig();
}
}
}
- public updateConfiguration(forceUpdate = false) {
- const newConfig = MarkdownPreviewEnhancedConfig.getCurrentConfig();
- if (forceUpdate || !this.config.isEqualTo(newConfig)) {
- const previewProviders = getAllPreviewProviders();
- // if `singlePreview` setting is changed, close all previews.
- if (this.config.singlePreview !== newConfig.singlePreview) {
- previewProviders.forEach((provider) => {
- provider.closeAllPreviews(this.config.singlePreview);
- });
-
- this.config = newConfig;
- } else {
- this.config = newConfig;
-
- const previewTheme = this.getPreviewTheme(
- newConfig.previewTheme,
- newConfig.previewColorScheme,
- );
- this.notebooks.forEach((notebook) => {
- notebook.updateConfig({ ...newConfig, previewTheme });
- });
- // update all generated md documents
- previewProviders.forEach((provider) => {
- provider.refreshAllPreviews();
- });
- }
+ public async updateWorkbenchEditorAssociationsBasedOnPreviewMode() {
+ const workbenchConfig = vscode.workspace.getConfiguration('workbench');
+ const previewMode = getMPEConfig('previewMode');
+ const markdownFileExtensions = getMPEConfig(
+ 'markdownFileExtensions',
+ ) ?? ['.md'];
+ const editorAssociations =
+ workbenchConfig.get<{ [key: string]: string }>('editorAssociations') ??
+ {};
+ let newEditorAssociations = { ...editorAssociations };
+ if (previewMode === PreviewMode.PreviewsOnly) {
+ const associations: { [key: string]: string } = {};
+ markdownFileExtensions.forEach((ext) => {
+ associations[`*${ext}`] = 'markdown-preview-enhanced';
+ });
+ // Add associations to editorAssociations
+ newEditorAssociations = { ...editorAssociations, ...associations };
+ } else {
+ // delete associations from editorAssociations
+ newEditorAssociations = Object.fromEntries(
+ Object.entries(editorAssociations).filter(([key]) => {
+ return !markdownFileExtensions.find((ext) => {
+ return key.endsWith(ext);
+ });
+ }),
+ );
+ }
+
+ if (
+ JSON.stringify(newEditorAssociations) !==
+ JSON.stringify(editorAssociations)
+ ) {
+ await workbenchConfig.update(
+ 'editorAssociations',
+ newEditorAssociations,
+ vscode.ConfigurationTarget.Global,
+ );
}
}
+ public async updateAllNotebooksConfig() {
+ const previewProviders = getAllPreviewProviders();
+ await this.updateWorkbenchEditorAssociationsBasedOnPreviewMode();
+ const newMPEConfig = MarkdownPreviewEnhancedConfig.getCurrentConfig();
+
+ // If previewMode changed, close all previews.
+ if (this.currentMPEConfig.previewMode !== newMPEConfig.previewMode) {
+ previewProviders.forEach((provider) => {
+ provider.closeAllPreviews(this.currentMPEConfig.previewMode);
+ });
+ }
+
+ // Update all notebooks config
+ await Promise.all(
+ this.notebooks.map(async (notebook) => {
+ const config = await this.loadNotebookConfig(notebook.notebookPath);
+ notebook.updateConfig(config);
+ }),
+ );
+
+ // Refresh all previews
+ previewProviders.forEach((provider) => {
+ provider.refreshAllPreviews();
+ });
+
+ this.currentMPEConfig = newMPEConfig;
+ }
+
private getPreviewThemeByLightOrDark(
theme: PreviewTheme,
color: 'light' | 'dark',
diff --git a/src/preview-custom-editor-provider.ts b/src/preview-custom-editor-provider.ts
new file mode 100644
index 0000000..5238a7b
--- /dev/null
+++ b/src/preview-custom-editor-provider.ts
@@ -0,0 +1,33 @@
+import * as vscode from 'vscode';
+import { PreviewProvider } from './preview-provider';
+
+export class PreviewCustomEditorProvider
+ implements vscode.CustomTextEditorProvider {
+ constructor(private context: vscode.ExtensionContext) {}
+
+ async resolveCustomTextEditor(
+ document: vscode.TextDocument,
+ webviewPanel: vscode.WebviewPanel,
+ token: vscode.CancellationToken,
+ ): Promise {
+ try {
+ const provider = await PreviewProvider.getPreviewContentProvider(
+ document.uri,
+ this.context,
+ );
+ return await provider.initPreview({
+ sourceUri: document.uri,
+ document,
+ // HACK: The `viewOptions` below will not actually be used.
+ viewOptions: {
+ viewColumn: webviewPanel.viewColumn ?? vscode.ViewColumn.One,
+ preserveFocus: true,
+ },
+ webviewPanel,
+ });
+ } catch (error) {
+ console.error(error);
+ vscode.window.showErrorMessage(error.message);
+ }
+ }
+}
diff --git a/src/preview-provider.ts b/src/preview-provider.ts
index 6bb7d85..20c9049 100644
--- a/src/preview-provider.ts
+++ b/src/preview-provider.ts
@@ -1,11 +1,14 @@
-import { Notebook, loadConfigsInDirectory, utility } from 'crossnote';
+import { Mutex } from 'async-mutex';
+import { ImageUploader, Notebook, PreviewMode, utility } from 'crossnote';
import { tmpdir } from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import { Uri } from 'vscode';
+import { getMPEConfig } from './config';
import NotebooksManager from './notebooks-manager';
import {
getCrossnoteVersion,
+ getPreviewMode,
getWorkspaceFolderUri,
globalConfigPath,
isMarkdownFile,
@@ -20,11 +23,8 @@ if (isVSCodeWebExtension()) {
console.debug('* Loading /crossnote directory at http://localhost:6789/');
utility.setCrossnoteBuildDirectory('http://localhost:6789/');
} else {
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
const jsdelivrCdnHost =
- config.get('jsdelivrCdnHost') ?? 'cdn.jsdelivr.net';
+ getMPEConfig('jsdelivrCdnHost') ?? 'cdn.jsdelivr.net';
utility.setCrossnoteBuildDirectory(
`https://${jsdelivrCdnHost}/npm/crossnote@${getCrossnoteVersion()}/out/`,
);
@@ -62,13 +62,16 @@ utility.useExternalAddFileProtocolFunction((filePath, preview) => {
});
/**
- * key is `workspaceDir`
+ * key is workspaceUri.toString()
* value is the `PreviewProvider`
*/
-const WORKSPACE_PREVIEW_PROVIDER_MAP: Map<
- string, // workspaceDir fsPath
- PreviewProvider
-> = new Map();
+const WORKSPACE_PREVIEW_PROVIDER_MAP: Map = new Map();
+
+/**
+ * key is workspaceUri.toString()
+ * value is the `Mutex`
+ */
+const WORKSPACE_MUTEX_MAP: Map = new Map();
export function getAllPreviewProviders(): PreviewProvider[] {
return Array.from(WORKSPACE_PREVIEW_PROVIDER_MAP.values());
@@ -79,6 +82,9 @@ export function getAllPreviewProviders(): PreviewProvider[] {
// https://github.com/Microsoft/vscode/tree/master/extensions/markdown/src
// https://github.com/tomoki1207/gfm-preview/blob/master/src/gfmProvider.ts
// https://github.com/cbreeden/vscode-markdownit
+/**
+ * One workspace folder has one PreviewProvider
+ */
export class PreviewProvider {
private waiting: boolean = false;
@@ -93,15 +99,15 @@ export class PreviewProvider {
private context: vscode.ExtensionContext;
/**
- * The key is markdown file fspath
+ * The key is sourceUri.toString()
* value is Preview (vscode.Webview) object
*/
- private previewMaps: { [key: string]: vscode.WebviewPanel } = {};
-
- private preview2EditorMap: Map<
+ private previewMaps: Map> = new Map();
+ private previewToDocumentMap: Map<
vscode.WebviewPanel,
- vscode.TextEditor
+ vscode.TextDocument
> = new Map();
+ private initializedPreviews: Set = new Set();
private static singlePreviewPanel: vscode.WebviewPanel | null;
private static singlePreviewPanelSourceUriTarget: Uri | null;
@@ -135,44 +141,45 @@ export class PreviewProvider {
return PreviewProvider.notebooksManager;
}
- public async updateCrossnoteConfig(directory: string, forceUpdate = false) {
- // If directory is globalConfigDirectory && ${workspaceDir}/.crossnote directory exists
- // then return without updating.
- if (
- directory === globalConfigPath &&
- (await this.notebook.fs.exists(
- path.join(this.notebook.notebookPath.fsPath, '.crossnote'),
- ))
- ) {
- return;
- }
-
- if ((await this.notebook.fs.exists(directory)) || forceUpdate) {
- const configs = await loadConfigsInDirectory(
- directory,
- this.notebook.fs,
- true,
- );
- this.notebook.updateConfig(configs);
- }
- }
-
public static async getPreviewContentProvider(
uri: vscode.Uri,
context: vscode.ExtensionContext,
) {
const workspaceUri = getWorkspaceFolderUri(uri);
- if (WORKSPACE_PREVIEW_PROVIDER_MAP.has(workspaceUri.fsPath)) {
- const provider = WORKSPACE_PREVIEW_PROVIDER_MAP.get(workspaceUri.fsPath);
- if (!provider) {
- throw new Error('Cannot find preview provider');
+
+ // Acquire mutex
+ let mutex: Mutex;
+ const mutexKey = workspaceUri.toString();
+ if (WORKSPACE_MUTEX_MAP.has(mutexKey)) {
+ const mutex_ = WORKSPACE_MUTEX_MAP.get(mutexKey);
+ if (!mutex_) {
+ throw new Error('Cannot find mutex');
}
- return provider;
+ mutex = mutex_;
} else {
- const provider = new PreviewProvider();
- await provider.init(context, workspaceUri);
- WORKSPACE_PREVIEW_PROVIDER_MAP.set(workspaceUri.fsPath, provider);
- return provider;
+ mutex = new Mutex();
+ WORKSPACE_MUTEX_MAP.set(mutexKey, mutex);
+ }
+
+ const release = await mutex.acquire();
+ try {
+ if (WORKSPACE_PREVIEW_PROVIDER_MAP.has(mutexKey)) {
+ const provider = WORKSPACE_PREVIEW_PROVIDER_MAP.get(mutexKey);
+ if (!provider) {
+ throw new Error('Cannot find preview provider');
+ }
+ release();
+ return provider;
+ } else {
+ const provider = new PreviewProvider();
+ await provider.init(context, workspaceUri);
+ WORKSPACE_PREVIEW_PROVIDER_MAP.set(mutexKey, provider);
+ release();
+ return provider;
+ }
+ } catch (error) {
+ release();
+ throw error;
}
}
@@ -181,28 +188,50 @@ export class PreviewProvider {
this.notebook.clearAllNoteMarkdownEngineCaches();
// refresh iframes
- if (useSinglePreview()) {
+ if (getPreviewMode() === PreviewMode.SinglePreview) {
this.refreshPreviewPanel(
PreviewProvider.singlePreviewPanelSourceUriTarget,
);
} else {
- for (const key in this.previewMaps) {
- if (this.previewMaps.hasOwnProperty(key)) {
- this.refreshPreviewPanel(vscode.Uri.file(key));
- }
+ for (const [sourceUriString] of this.previewMaps) {
+ this.refreshPreviewPanel(vscode.Uri.parse(sourceUriString));
}
}
}
+ private addPreviewToMap(sourceUri: Uri, previewPanel: vscode.WebviewPanel) {
+ let previews = this.previewMaps.get(sourceUri.toString());
+ if (!previews) {
+ previews = new Set();
+ this.previewMaps.set(sourceUri.toString(), previews);
+ }
+ previews.add(previewPanel);
+ }
+
+ private deletePreviewFromMap(
+ sourceUri: Uri,
+ previewPanel: vscode.WebviewPanel,
+ ) {
+ this.previewMaps.get(sourceUri.toString())?.delete(previewPanel);
+ }
+
/**
- * return markdown preview of sourceUri
+ * return markdown previews of sourceUri
* @param sourceUri
*/
- public getPreview(sourceUri: Uri): vscode.WebviewPanel | null {
- if (useSinglePreview()) {
- return PreviewProvider.singlePreviewPanel;
+ public getPreviews(sourceUri: Uri): vscode.WebviewPanel[] | null | undefined {
+ if (
+ getPreviewMode() === PreviewMode.SinglePreview &&
+ PreviewProvider.singlePreviewPanel
+ ) {
+ return [PreviewProvider.singlePreviewPanel];
} else {
- return this.previewMaps[sourceUri.fsPath];
+ const previews = this.previewMaps.get(sourceUri.toString());
+ if (previews) {
+ return Array.from(previews);
+ } else {
+ return null;
+ }
}
}
@@ -211,24 +240,28 @@ export class PreviewProvider {
* @param textEditor
*/
public isPreviewOn(sourceUri: Uri) {
- if (useSinglePreview()) {
+ if (getPreviewMode() === PreviewMode.SinglePreview) {
return !!PreviewProvider.singlePreviewPanel;
} else {
- return !!this.getPreview(sourceUri);
+ const previews = this.getPreviews(sourceUri);
+ return previews && previews.length > 0;
}
}
public destroyPreview(sourceUri: Uri) {
- if (useSinglePreview()) {
+ const previewMode = getPreviewMode();
+ if (previewMode === PreviewMode.SinglePreview) {
PreviewProvider.singlePreviewPanel = null;
PreviewProvider.singlePreviewPanelSourceUriTarget = null;
- this.preview2EditorMap = new Map();
- this.previewMaps = {};
+ this.previewToDocumentMap = new Map();
+ this.previewMaps = new Map();
} else {
- const previewPanel = this.getPreview(sourceUri);
- if (previewPanel) {
- this.preview2EditorMap.delete(previewPanel);
- delete this.previewMaps[sourceUri.fsPath];
+ const previews = this.getPreviews(sourceUri);
+ if (previews) {
+ previews.forEach((preview) => {
+ this.previewToDocumentMap.delete(preview);
+ this.deletePreviewFromMap(sourceUri, preview);
+ });
}
}
}
@@ -242,14 +275,27 @@ export class PreviewProvider {
return this.notebook.getNoteMarkdownEngine(sourceUri.fsPath);
}
- public async initPreview(
- sourceUri: vscode.Uri,
- editor: vscode.TextEditor,
- viewOptions: { viewColumn: vscode.ViewColumn; preserveFocus?: boolean },
- ) {
- const isUsingSinglePreview = useSinglePreview();
+ public async initPreview({
+ sourceUri,
+ document,
+ webviewPanel,
+ activeLine,
+ viewOptions,
+ }: {
+ sourceUri: vscode.Uri;
+ document: vscode.TextDocument;
+ webviewPanel?: vscode.WebviewPanel;
+ activeLine?: number;
+ viewOptions: { viewColumn: vscode.ViewColumn; preserveFocus?: boolean };
+ }): Promise {
+ // console.log('@initPreview: ', sourceUri);
+ const previewMode = getPreviewMode();
let previewPanel: vscode.WebviewPanel;
- if (isUsingSinglePreview && PreviewProvider.singlePreviewPanel) {
+ const previews = this.getPreviews(sourceUri);
+ if (
+ previewMode === PreviewMode.SinglePreview &&
+ PreviewProvider.singlePreviewPanel
+ ) {
const oldResourceRoot = PreviewProvider.singlePreviewPanelSourceUriTarget
? getWorkspaceFolderUri(
PreviewProvider.singlePreviewPanelSourceUriTarget,
@@ -261,13 +307,29 @@ export class PreviewProvider {
PreviewProvider.singlePreviewPanel = null;
PreviewProvider.singlePreviewPanelSourceUriTarget = null;
singlePreview.dispose();
- return this.initPreview(sourceUri, editor, viewOptions);
+ return await this.initPreview({
+ sourceUri,
+ document,
+ viewOptions,
+ activeLine,
+ });
} else {
previewPanel = PreviewProvider.singlePreviewPanel;
PreviewProvider.singlePreviewPanelSourceUriTarget = sourceUri;
}
- } else if (this.previewMaps[sourceUri.fsPath]) {
- previewPanel = this.previewMaps[sourceUri.fsPath];
+ } else if (previews && previews.length > 0 && !webviewPanel) {
+ await Promise.all(
+ previews.map((preview) =>
+ this.initPreview({
+ sourceUri,
+ document,
+ webviewPanel: preview,
+ viewOptions,
+ activeLine,
+ }),
+ ),
+ );
+ return;
} else {
const localResourceRoots = [
vscode.Uri.file(this.context.extensionPath),
@@ -280,127 +342,153 @@ export class PreviewProvider {
localResourceRoots.push(workspaceUri);
}
- previewPanel = vscode.window.createWebviewPanel(
- 'markdown-preview-enhanced',
- `Preview ${path.basename(sourceUri.fsPath)}`,
- viewOptions,
- {
- enableFindWidget: true,
+ if (webviewPanel) {
+ previewPanel = webviewPanel;
+ previewPanel.webview.options = {
+ enableScripts: true,
localResourceRoots,
- enableScripts: true, // TODO: This might be set by enableScriptExecution config. But for now we just enable it.
- },
- );
+ };
+ // @ts-ignore
+ previewPanel.options.retainContextWhenHidden = true;
+ } else {
+ previewPanel = vscode.window.createWebviewPanel(
+ 'markdown-preview-enhanced',
+ `Preview ${path.basename(sourceUri.fsPath)}`,
+ viewOptions,
+ {
+ enableFindWidget: true,
+ localResourceRoots,
+ enableScripts: true, // TODO: This might be set by enableScriptExecution config. But for now we just enable it.
+ retainContextWhenHidden: true,
+ },
+ );
+ }
// set icon
+ // NOTE: This doesn't work for custom editor.
previewPanel.iconPath = vscode.Uri.file(
path.join(this.context.extensionPath, 'media', 'preview.svg'),
);
- // register previewPanel message events
- previewPanel.webview.onDidReceiveMessage(
- (message) => {
- // console.log('@ onDidReceiveMessage: ', message);
- vscode.commands.executeCommand(
- `_crossnote.${message.command}`,
- ...message.args,
- );
- },
- null,
- this.context.subscriptions,
- );
-
- // unregister previewPanel
- previewPanel.onDidDispose(
- () => {
- this.destroyPreview(sourceUri);
- this.destroyEngine(sourceUri);
- },
- null,
- this.context.subscriptions,
- );
+ // NOTE: We only register for the webview event listeners once.
+ if (!this.initializedPreviews.has(previewPanel)) {
+ this.initializedPreviews.add(previewPanel);
+
+ // register previewPanel message events.
+ previewPanel.webview.onDidReceiveMessage(
+ (message) => {
+ // console.log('@ receiveMessage: ', message, previewPanel);
+ vscode.commands.executeCommand(
+ `_crossnote.${message.command}`,
+ ...message.args,
+ );
+ },
+ null,
+ this.context.subscriptions,
+ );
+
+ // unregister previewPanel.
+ previewPanel.onDidDispose(
+ () => {
+ this.destroyPreview(sourceUri);
+ this.destroyEngine(sourceUri);
+ this.initializedPreviews.delete(previewPanel);
+ },
+ null,
+ this.context.subscriptions,
+ );
+ }
- if (isUsingSinglePreview) {
+ if (previewMode === PreviewMode.SinglePreview) {
PreviewProvider.singlePreviewPanel = previewPanel;
PreviewProvider.singlePreviewPanelSourceUriTarget = sourceUri;
}
}
// register previewPanel
- this.previewMaps[sourceUri.fsPath] = previewPanel;
- this.preview2EditorMap.set(previewPanel, editor);
+ this.addPreviewToMap(sourceUri, previewPanel);
+ this.previewToDocumentMap.set(previewPanel, document);
// set title
previewPanel.title = `Preview ${path.basename(sourceUri.fsPath)}`;
// init markdown engine
let initialLine: number | undefined;
- if (editor && editor.document.uri.fsPath === sourceUri.fsPath) {
- initialLine = await new Promise((resolve, reject) => {
- // HACK: sometimes we only get 0. I couldn't find API to wait for editor getting loaded.
- setTimeout(() => {
- return resolve(editor.selections[0].active.line || 0);
- }, 100);
- });
+ if (document.uri.fsPath === sourceUri.fsPath) {
+ initialLine = activeLine;
}
- const text = editor.document.getText();
+ const inputString = document.getText() ?? '';
const engine = this.getEngine(sourceUri);
- engine
- .generateHTMLTemplateForPreview({
- inputString: text,
+ try {
+ const html = await engine.generateHTMLTemplateForPreview({
+ inputString,
config: {
sourceUri: sourceUri.toString(),
- initialLine: initialLine as number,
+ initialLine,
isVSCode: true,
- scrollSync: this.getNotebooksManager().config.scrollSync,
- imageUploader: this.getNotebooksManager().config.imageUploader,
+ scrollSync: getMPEConfig('scrollSync'),
+ imageUploader: getMPEConfig('imageUploader'),
},
contentSecurityPolicy: '',
vscodePreviewPanel: previewPanel,
isVSCodeWebExtension: isVSCodeWebExtension(),
- })
- .then((html) => {
- previewPanel.webview.html = html;
});
+ previewPanel.webview.html = html;
+ } catch (error) {
+ vscode.window.showErrorMessage(error.toString());
+ console.error(error);
+ }
}
/**
- * Close all previews
+ * Close all previews.
*/
- public closeAllPreviews(singlePreview: boolean) {
- if (singlePreview) {
+ public closeAllPreviews(previewMode: PreviewMode) {
+ if (previewMode === PreviewMode.SinglePreview) {
if (PreviewProvider.singlePreviewPanel) {
PreviewProvider.singlePreviewPanel.dispose();
}
} else {
- const previewPanels: vscode.WebviewPanel[] = [];
- for (const key in this.previewMaps) {
- if (this.previewMaps.hasOwnProperty(key)) {
- const previewPanel = this.previewMaps[key];
- if (previewPanel) {
- previewPanels.push(previewPanel);
- }
+ for (const [sourceUriString] of this.previewMaps) {
+ const previews = this.previewMaps.get(sourceUriString);
+ if (previews) {
+ previews.forEach((preview) => preview.dispose());
}
}
-
- previewPanels.forEach((previewPanel) => previewPanel.dispose());
}
- this.previewMaps = {};
- this.preview2EditorMap = new Map();
+ this.previewMaps = new Map();
+ this.previewToDocumentMap = new Map();
// this.engineMaps = {};
PreviewProvider.singlePreviewPanel = null;
PreviewProvider.singlePreviewPanelSourceUriTarget = null;
}
- public postMessageToPreview(
+ public async postMessageToPreview(
sourceUri: Uri,
- message: { command: string; [key: string]: any }, // TODO: Define a type for message
+ message: { command: string; [key: string]: any }, // TODO: Define a type for message.
) {
- const preview = this.getPreview(sourceUri);
- if (preview) {
- // console.log('@ postMessageToPreview: ', preview, message);
- preview.webview.postMessage(message);
+ const previews = this.getPreviews(sourceUri);
+ if (previews) {
+ // console.log(
+ // '@ postMessageToPreview: ',
+ // sourceUri.fsPath,
+ // message,
+ // previews,
+ // );
+
+ for (let i = 0; i < previews.length; i++) {
+ const preview = previews[i];
+ if (preview.visible) {
+ const result = await preview.webview.postMessage(message);
+ if (!result) {
+ console.error(
+ `Failed to send message "${message.command}" to preview panel for ${sourceUri.fsPath}`,
+ );
+ }
+ }
+ }
}
}
@@ -417,8 +505,9 @@ export class PreviewProvider {
public updateMarkdown(sourceUri: Uri, triggeredBySave?: boolean) {
const engine = this.getEngine(sourceUri);
- const previewPanel = this.getPreview(sourceUri);
- if (!previewPanel) {
+ const previews = this.getPreviews(sourceUri);
+ // console.log('updateMarkdown: ', previews?.length);
+ if (!previews || !previews.length) {
return;
}
@@ -428,34 +517,44 @@ export class PreviewProvider {
}
// not presentation mode
- vscode.workspace.openTextDocument(sourceUri).then((document) => {
+ vscode.workspace.openTextDocument(sourceUri).then(async (document) => {
const text = document.getText();
- this.postMessageToPreview(sourceUri, {
+ await this.postMessageToPreview(sourceUri, {
command: 'startParsingMarkdown',
});
- const preview = this.getPreview(sourceUri);
- engine
- .parseMD(text, {
- isForPreview: true,
- useRelativeFilePath: false,
- hideFrontMatter: false,
- triggeredBySave,
- vscodePreviewPanel: preview,
- })
- .then(({ markdown, html, tocHTML, JSAndCssFiles, yamlConfig }) => {
+ const previews = this.getPreviews(sourceUri);
+ if (!previews || !previews.length) {
+ return;
+ }
+ for (let i = 0; i < previews.length; i++) {
+ try {
+ const preview = previews[0];
+ const {
+ html,
+ tocHTML,
+ JSAndCssFiles,
+ yamlConfig,
+ } = await engine.parseMD(text, {
+ isForPreview: true,
+ useRelativeFilePath: false,
+ hideFrontMatter: false,
+ triggeredBySave,
+ vscodePreviewPanel: preview, // TODO:
+ });
// check JSAndCssFiles
if (
JSON.stringify(JSAndCssFiles) !==
- JSON.stringify(this.jsAndCssFilesMaps[sourceUri.fsPath]) ||
+ JSON.stringify(this.jsAndCssFilesMaps[sourceUri.fsPath] ?? []) ||
yamlConfig['isPresentationMode']
) {
this.jsAndCssFilesMaps[sourceUri.fsPath] = JSAndCssFiles;
// restart iframe
this.refreshPreview(sourceUri);
} else {
- this.postMessageToPreview(sourceUri, {
+ await this.postMessageToPreview(sourceUri, {
command: 'updateHtml',
+ markdown: text,
html,
tocHTML,
totalLineCount: document.lineCount,
@@ -475,30 +574,38 @@ export class PreviewProvider {
} ${isVSCodeWebExtension() ? 'vscode-web-extension' : ''}`,
});
}
- })
- .catch((error) => {
- vscode.window.showErrorMessage(error.toString());
- });
+ break;
+ } catch (error) {
+ if (i === previews.length - 1) {
+ // This is the
+ vscode.window.showErrorMessage(error.toString());
+ } else {
+ continue;
+ }
+ }
+ }
});
}
- public refreshPreviewPanel(sourceUri: Uri | null) {
+ private refreshPreviewPanel(sourceUri: Uri | null) {
if (!sourceUri) {
return;
}
- this.preview2EditorMap.forEach((editor, previewPanel) => {
+ this.previewToDocumentMap.forEach(async (document, previewPanel) => {
if (
previewPanel &&
- editor &&
- editor.document &&
- isMarkdownFile(editor.document) &&
- editor.document.uri &&
- editor.document.uri.fsPath === sourceUri.fsPath
+ isMarkdownFile(document) &&
+ document.uri &&
+ document.uri.fsPath === sourceUri.fsPath
) {
- this.initPreview(sourceUri, editor, {
- viewColumn: previewPanel.viewColumn ?? vscode.ViewColumn.One,
- preserveFocus: true,
+ await this.initPreview({
+ sourceUri,
+ document,
+ viewOptions: {
+ viewColumn: previewPanel.viewColumn ?? vscode.ViewColumn.One,
+ preserveFocus: true,
+ },
});
}
});
@@ -683,10 +790,8 @@ export class PreviewProvider {
}
public update(sourceUri: Uri) {
- if (
- !this.getNotebooksManager().config.liveUpdate ||
- !this.getPreview(sourceUri)
- ) {
+ const previews = this.getPreviews(sourceUri);
+ if (!getMPEConfig('liveUpdate') || !previews || !previews.length) {
return;
}
@@ -700,34 +805,26 @@ export class PreviewProvider {
}
}
- public openImageHelper(sourceUri: Uri) {
+ public async openImageHelper(sourceUri: Uri) {
if (sourceUri.scheme === 'markdown-preview-enhanced') {
return vscode.window.showWarningMessage('Please focus a markdown file.');
} else if (!this.isPreviewOn(sourceUri)) {
return vscode.window.showWarningMessage('Please open preview first.');
} else {
- return this.postMessageToPreview(sourceUri, {
+ return await this.postMessageToPreview(sourceUri, {
command: 'openImageHelper',
});
}
}
}
-/**
- * check whehter to use only one preview or not
- */
-export function useSinglePreview() {
- const config = vscode.workspace.getConfiguration('markdown-preview-enhanced');
- return config.get('singlePreview');
-}
-
export function getPreviewUri(uri: vscode.Uri) {
if (uri.scheme === 'markdown-preview-enhanced') {
return uri;
}
let previewUri: Uri;
- if (useSinglePreview()) {
+ if (getPreviewMode() === PreviewMode.SinglePreview) {
previewUri = uri.with({
scheme: 'markdown-preview-enhanced',
path: 'single-preview.rendered',
diff --git a/src/utils.ts b/src/utils.ts
index e5782b1..a25fd4d 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -1,12 +1,15 @@
import path = require('path');
+import { PreviewMode } from 'crossnote';
import * as os from 'os';
import * as vscode from 'vscode';
import * as packageJSON from '../package.json';
+import { getMPEConfig } from './config';
/**
* Format pathString if it is on Windows. Convert `c:\` like string to `C:\`
* @param pathString
*/
+/*
function formatPathIfNecessary(pathString: string) {
if (process.platform === 'win32') {
pathString = pathString.replace(
@@ -16,6 +19,7 @@ function formatPathIfNecessary(pathString: string) {
}
return pathString;
}
+*/
/**
* Get the workspace folder uri of the given uri
@@ -42,9 +46,8 @@ export function getWorkspaceFolderUri(uri: vscode.Uri) {
}
function getGlobalConfigPath(): string {
- const config = vscode.workspace.getConfiguration('markdown-preview-enhanced');
- const configPath = config.get('configPath');
- if (configPath && configPath !== '') {
+ const configPath = getMPEConfig('configPath');
+ if (typeof configPath === 'string' && configPath && configPath !== '') {
return configPath.replace(/^~/, os.homedir());
}
@@ -70,11 +73,8 @@ export function isMarkdownFile(document: vscode.TextDocument) {
if (!flag) {
// Check file extension
- const config = vscode.workspace.getConfiguration(
- 'markdown-preview-enhanced',
- );
const markdownFileExtensions =
- config.get('markdownFileExtensions') ?? [];
+ getMPEConfig('markdownFileExtensions') ?? [];
const fileName = document.fileName;
const ext = path.extname(fileName).toLowerCase();
flag = markdownFileExtensions.includes(ext);
@@ -137,3 +137,11 @@ export function isVSCodewebExtensionDevMode() {
export function getCrossnoteVersion() {
return packageJSON.dependencies['crossnote'];
}
+
+export function getPreviewMode() {
+ return getMPEConfig('previewMode');
+}
+
+export function getEditorActiveLine(editor: vscode.TextEditor) {
+ return editor.selections[0].active.line ?? 0;
+}
diff --git a/yarn.lock b/yarn.lock
index 615b7ed..a391c14 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -276,6 +276,20 @@
dependencies:
prop-types "^15.7.2"
+"@monaco-editor/loader@^1.3.3":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.4.0.tgz#f08227057331ec890fa1e903912a5b711a2ad558"
+ integrity sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==
+ dependencies:
+ state-local "^1.0.6"
+
+"@monaco-editor/react@^4.5.2":
+ version "4.5.2"
+ resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.5.2.tgz#e8cc802203f729b423a998ea6fcb466604d61258"
+ integrity sha512-emcWu6vg1OpXPiYll4aPOaXe8bwYB4UaaNTwtArFLgMoNGBzRZb2Xn0Bra2HMIFM7QLgs7fCGunHO5LkfT2LBA==
+ dependencies:
+ "@monaco-editor/loader" "^1.3.3"
+
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -309,15 +323,15 @@
picocolors "^1.0.0"
tslib "^2.6.0"
-"@puppeteer/browsers@1.7.0":
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.7.0.tgz#714a25ad6963f5478e36004ea7eda254870a4659"
- integrity sha512-sl7zI0IkbQGak/+IE3VEEZab5SSOlI5F6558WvzWGC1n3+C722rfewC1ZIkcF9dsoGSsxhsONoseVlNQG4wWvQ==
+"@puppeteer/browsers@1.7.1":
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.7.1.tgz#04f1e3aec4b87f50a7acc8f64be2149bda014f0a"
+ integrity sha512-nIb8SOBgDEMFY2iS2MdnUZOg2ikcYchRrBoF+wtdjieRFKR2uGRipHY/oFLo+2N6anDualyClPzGywTHRGrLfw==
dependencies:
debug "4.3.4"
extract-zip "2.0.1"
progress "2.0.3"
- proxy-agent "6.3.0"
+ proxy-agent "6.3.1"
tar-fs "3.0.4"
unbzip2-stream "1.4.3"
yargs "17.7.1"
@@ -329,6 +343,11 @@
dependencies:
any-observable "^0.3.0"
+"@sanity/diff-match-patch@^3.1.1":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@sanity/diff-match-patch/-/diff-match-patch-3.1.1.tgz#16514d3a550d880bae1f59cc3ffe6865f5a4b58a"
+ integrity sha512-dSZqGeYjHKGIkqAzGqLcG92LZyJGX+nYbs/FWawhBbTBDWi21kvQ0hsL3DJThuFVWtZMWTQijN3z6Cnd44Pf2g==
+
"@tootallnate/quickjs-emscripten@^0.23.0":
version "0.23.0"
resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c"
@@ -341,11 +360,6 @@
dependencies:
"@types/node" "*"
-"@types/clone@~2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@types/clone/-/clone-2.1.1.tgz#9b880d0ce9b1f209b5e0bd6d9caa38209db34024"
- integrity sha512-BZIU34bSYye0j/BFcPraiDZ5ka6MJADjcDVELGf7glr9K+iE8NYVjFslJFVWzskSxkLLyCrSPScE82/UUoBSvg==
-
"@types/crypto-js@^4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.2.tgz#fb56b34f397d9ae2335611e416f15e7d65e276e6"
@@ -357,21 +371,21 @@
integrity sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==
"@types/d3-scale@^4.0.3":
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.4.tgz#3c5e2263eea5a3670cd91043b9f4d150a94c43f1"
- integrity sha512-eq1ZeTj0yr72L8MQk6N6heP603ubnywSDRfNpi5enouR112HzGLS6RIvExCzZTraFF4HdzNpJMwA/zGiMoHUUw==
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.5.tgz#daa4faa5438315a37a1f5eb1bcdc5aeb3d3e5a2d"
+ integrity sha512-w/C++3W394MHzcLKO2kdsIn5KKNTOqeQVzyPSGPLzQbkPw/jpeaGtSRlakcKevGgGsjJxGsbqS0fPrVFDbHrDA==
dependencies:
"@types/d3-time" "*"
"@types/d3-time@*":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819"
- integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.1.tgz#f0c8f9037632cc4511ae55e7e1459dcb95fb3619"
+ integrity sha512-5j/AnefKAhCw4HpITmLDTPlf4vhi8o/dES+zbegfPb7LaGfNyqkLxBR6E+4yvTAgnJLmhe80EXFMzUs38fw4oA==
"@types/debug@^4.0.0":
- version "4.1.8"
- resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317"
- integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==
+ version "4.1.9"
+ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.9.tgz#906996938bc672aaf2fb8c0d3733ae1dda05b005"
+ integrity sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==
dependencies:
"@types/ms" "*"
@@ -483,9 +497,9 @@
integrity sha512-qK/CmOdS2o7ry3k6YqU4zD3R2AYlJfbwBoSbKpBoP+GpXNE+0NEgJOli4n0bm0diK5kfBnchgCEj4igQz/44Hg==
"@types/yauzl@^2.9.1":
- version "2.10.0"
- resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599"
- integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==
+ version "2.10.1"
+ resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.1.tgz#4e8f299f0934d60f36c74f59cb5a8483fd786691"
+ integrity sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==
dependencies:
"@types/node" "*"
@@ -575,9 +589,9 @@
eslint-visitor-keys "^3.4.1"
"@viz-js/viz@^3.1.0":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@viz-js/viz/-/viz-3.1.0.tgz#f192a4f98f1fa187b959f2f54d169531677a0d99"
- integrity sha512-rQi2PL9HoqTpE5DVodGgSLRdRVkDVgTG36AdcUR8EWxHL45KoUw7PAzZLm70vgK+QbUN6nCraTtqgxyqeJzxBA==
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@viz-js/viz/-/viz-3.2.0.tgz#fc912f8f95aace478c391bebeedd3a3a7a86ac17"
+ integrity sha512-CWSfQKrwt9ZrLTUK4rqhqfkdkk89rnsp7hnt3sPs01GmgA9kU2yBUwMYMmb+/w8zKFut/ZtLcMeLeaAQrZ9oOg==
"@vscode/test-web@^0.0.45":
version "0.0.45"
@@ -772,7 +786,7 @@ acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
-agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0:
+agent-base@^7.0.2, agent-base@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434"
integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==
@@ -1107,13 +1121,13 @@ atob@^2.1.2:
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
autoprefixer@^10.4.13:
- version "10.4.15"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530"
- integrity sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==
+ version "10.4.16"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.16.tgz#fad1411024d8670880bdece3970aa72e3572feb8"
+ integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==
dependencies:
browserslist "^4.21.10"
- caniuse-lite "^1.0.30001520"
- fraction.js "^4.2.0"
+ caniuse-lite "^1.0.30001538"
+ fraction.js "^4.3.6"
normalize-range "^0.1.2"
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
@@ -1294,7 +1308,7 @@ browserify-zlib@^0.1.4:
dependencies:
pako "~0.2.0"
-browserslist@^4.14.5, browserslist@^4.21.10:
+browserslist@^4.14.5:
version "4.21.10"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0"
integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==
@@ -1304,6 +1318,16 @@ browserslist@^4.14.5, browserslist@^4.21.10:
node-releases "^2.0.13"
update-browserslist-db "^1.0.11"
+browserslist@^4.21.10:
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.0.tgz#6adc8116589ccea8a99d0df79c5de2436199abdb"
+ integrity sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA==
+ dependencies:
+ caniuse-lite "^1.0.30001539"
+ electron-to-chromium "^1.4.530"
+ node-releases "^2.0.13"
+ update-browserslist-db "^1.0.13"
+
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
@@ -1409,10 +1433,15 @@ caniuse-lite@^1.0.30001517:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz#d2e8fdec6116ffa36284ca2c33ef6d53612fe1c8"
integrity sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==
-caniuse-lite@^1.0.30001520:
- version "1.0.30001532"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz#c6a4d5d2da6d2b967f0ee5e12e7f680db6ad2fca"
- integrity sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==
+caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001539:
+ version "1.0.30001540"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001540.tgz#a316ca4f2ae673ab02ff0ec533334016d56ff658"
+ integrity sha512-9JL38jscuTJBTcuETxm8QLsFr/F6v0CYYTEU6r5+qSM98P2Q0Hmu0eG1dTG5GBUmywU3UlcVOUSIJYY47rdFSw==
+
+case-anything@^2.1.13:
+ version "2.1.13"
+ resolved "https://registry.yarnpkg.com/case-anything/-/case-anything-2.1.13.tgz#0cdc16278cb29a7fcdeb072400da3f342ba329e9"
+ integrity sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==
caseless@~0.12.0:
version "0.12.0"
@@ -1528,12 +1557,13 @@ chrome-trace-event@^1.0.2:
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
-chromium-bidi@0.4.22:
- version "0.4.22"
- resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.22.tgz#625dab72946e177f538da2d2b8a681652ef916da"
- integrity sha512-wR7Y9Ioez+cNXT4ZP7VNM1HRTljpNnMSLw4/RnwhhZUP4yCU7kIQND00YiktuHekch68jklGPK1q9Jkb29+fQg==
+chromium-bidi@0.4.28:
+ version "0.4.28"
+ resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.28.tgz#05befef4f3f19003198237245780d1c60e6f4dbc"
+ integrity sha512-2HZ74QlAApJrEwcGlU/sUu0s4VS+FI3CJ09Toc9aE9VemMyhHZXeaROQgJKNRaYMUTUx6qIv1cLBs3F+vfgjSw==
dependencies:
mitt "3.0.1"
+ urlpattern-polyfill "9.0.0"
class-utils@^0.3.5:
version "0.3.6"
@@ -1621,7 +1651,7 @@ clone-stats@^1.0.0:
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
integrity sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==
-clone@^2.1.1, clone@~2.1.2:
+clone@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
@@ -1890,18 +1920,21 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
-crossnote@^0.8.16:
- version "0.8.16"
- resolved "https://registry.yarnpkg.com/crossnote/-/crossnote-0.8.16.tgz#9e0ffc810cdf8a0276c34c7a66838df63549bb07"
- integrity sha512-SI4gl19HJFuwiXuJSb5CX2N6g+DkYouuzy1MjQ3Rri9OLGPzuQvc5NOGdPYFQXTuxVBSvLna/nL/6Y0NutyVqQ==
+crossnote@^0.8.18:
+ version "0.8.18"
+ resolved "https://registry.yarnpkg.com/crossnote/-/crossnote-0.8.18.tgz#806a37f6ff8627cada55ee645b9e8c1e2307479d"
+ integrity sha512-LvhWOU3/T6BAoDrWC/5I7XgnC/PMvKZJFyVBnrl/l5+OZtNw4QTU0jx+Q3dge2HCpER7xdApQo0ITZWER8Xm9g==
dependencies:
"@headlessui/react" "^1.7.17"
"@heroicons/react" "^2.0.18"
"@mdi/js" "^7.2.96"
"@mdi/react" "^1.6.1"
+ "@monaco-editor/react" "^4.5.2"
+ "@sanity/diff-match-patch" "^3.1.1"
"@viz-js/viz" "^3.1.0"
async-mutex "^0.4.0"
bit-field "^1.8.0"
+ case-anything "^2.1.13"
cheerio "^1.0.0-rc.12"
chrome-paths "^1.0.1"
classnames "^2.3.2"
@@ -1914,7 +1947,7 @@ crossnote@^0.8.16:
html-react-parser "^4.2.2"
imagemagick-cli "^0.5.0"
jquery "^3.7.1"
- katex "^0.16.8"
+ katex "^0.16.9"
less "^4.2.0"
markdown-it "^13.0.1"
markdown-it-abbr "^1.0.4"
@@ -1929,6 +1962,7 @@ crossnote@^0.8.16:
mermaid "^10.4.0"
minisearch "^6.1.0"
mkdirp "^3.0.1"
+ monaco-editor "^0.43.0"
object-hash "^3.0.0"
onml "^2.1.0"
pako "^2.1.0"
@@ -1939,10 +1973,10 @@ crossnote@^0.8.16:
react "^18.2.0"
react-contexify "^6.0.0"
react-dom "^18.2.0"
+ reading-time "^1.5.0"
request "^2.88.0"
simple-icons "^9.13.0"
slash "^5.1.0"
- snake-case "^3.0.4"
sval "^0.4.8"
temp "^0.9.0"
twemoji "^13.1.0"
@@ -2320,9 +2354,9 @@ dagre-d3-es@7.0.10:
lodash-es "^4.17.21"
daisyui@^3.7.3:
- version "3.7.3"
- resolved "https://registry.yarnpkg.com/daisyui/-/daisyui-3.7.3.tgz#247cfefa0112c31679af9035eff65e1bd866f062"
- integrity sha512-gKlz3RwfaukZxf8nQZsDAZ7quUSi7F8HjGGB34tkHruvfQB9cgVDQsmqUqSQtkAJYvzbrg/3dLUa9+5jF4iC1A==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/daisyui/-/daisyui-3.8.0.tgz#e61f77bb52a2d7f45e3bf2d9f6b0897144caa9d1"
+ integrity sha512-VsWD//XlHkOBFSiRNTOZTxTJ/W8xI65erowErfbDWrPTkMYqf0ee/FTaqn4rquZoCcumENdFegAL8eELMnztxQ==
dependencies:
colord "^2.9"
css-selector-tokenizer "^0.8"
@@ -2355,9 +2389,9 @@ date-fns@^2.30.0:
"@babel/runtime" "^7.21.0"
dayjs@^1.11.7:
- version "1.11.9"
- resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
- integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
+ version "1.11.10"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
+ integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
@@ -2566,10 +2600,10 @@ detect-newline@^4.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.0.tgz#450ac3f864d5f61112b53a524123b012c59581bc"
integrity sha512-1aXUEPdfGdzVPFpzGJJNgq9o81bGg1s09uxTWsqBlo9PI332uyJRQq13+LK/UN4JfxJbFdCXonUFQ9R/p7yCtw==
-devtools-protocol@0.0.1159816:
- version "0.0.1159816"
- resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1159816.tgz#b5848e8597de01e4738589e7553674c7312c8d2a"
- integrity sha512-2cZlHxC5IlgkIWe2pSDmCrDiTzbSJWywjbDDnupOImEBcG31CQgBLV8wWE+5t+C4rimcjHsbzy7CBzf9oFjboA==
+devtools-protocol@0.0.1179426:
+ version "0.0.1179426"
+ resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1179426.tgz#c4c3ee671efae868395569123002facbbbffa267"
+ integrity sha512-KKC7IGwdOr7u9kTGgjUvGTov/z1s2H7oHi3zKCdR9eSDyCPia5CBi4aRhtp7d8uR7l0GS5UTDw3TjKGu5CqINg==
didyoumean@^1.2.2:
version "1.2.2"
@@ -2645,14 +2679,6 @@ domutils@^3.0.1, domutils@^3.1.0:
domelementtype "^2.3.0"
domhandler "^5.0.3"
-dot-case@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
- integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
- dependencies:
- no-case "^3.0.4"
- tslib "^2.0.3"
-
duplexify@^3.5.0, duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
@@ -2689,6 +2715,11 @@ electron-to-chromium@^1.4.477:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz#5641ff2f5ba11df4bd960fe6a2f9f70aa8b9af96"
integrity sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==
+electron-to-chromium@^1.4.530:
+ version "1.4.531"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.531.tgz#22966d894c4680726c17cf2908ee82ff5d26ac25"
+ integrity sha512-H6gi5E41Rn3/mhKlPaT1aIMg/71hTAqn0gYEllSuw9igNWtvQwu185jiCZoZD29n7Zukgh7GVZ3zGf0XvkhqjQ==
+
elegant-spinner@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
@@ -3203,7 +3234,7 @@ fancy-log@^1.3.2:
parse-node-version "^1.0.0"
time-stamp "^1.0.0"
-fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3, fast-deep-equal@~3.1.3:
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
@@ -3224,7 +3255,7 @@ fast-glob@^3.0.3, fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0:
merge2 "^1.3.0"
micromatch "^4.0.4"
-fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@~2.1.0:
+fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
@@ -3450,7 +3481,7 @@ formstream@^1.1.0:
mime "^2.5.2"
pause-stream "~0.0.11"
-fraction.js@^4.2.0:
+fraction.js@^4.3.6:
version "4.3.6"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d"
integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==
@@ -4121,7 +4152,7 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
-https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1:
+https-proxy-agent@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab"
integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==
@@ -4129,6 +4160,14 @@ https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1:
agent-base "^7.0.2"
debug "4"
+https-proxy-agent@^7.0.2:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b"
+ integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==
+ dependencies:
+ agent-base "^7.0.2"
+ debug "4"
+
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
@@ -4885,10 +4924,10 @@ karma-chrome-launcher@^2.2.0:
fs-access "^1.0.0"
which "^1.2.1"
-katex@^0.16.8:
- version "0.16.8"
- resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.8.tgz#89b453f40e8557f423f31a1009e9298dd99d5ceb"
- integrity sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==
+katex@^0.16.9:
+ version "0.16.9"
+ resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.9.tgz#bc62d8f7abfea6e181250f85a56e4ef292dcb1fa"
+ integrity sha512-fsSYjWS0EEOwvy81j3vRA8TEAhQhKiqO+FQaKWp0m39qwOzHVBgAUBIXWj1pB+O2W3fIpNa6Y9KSKCVbfPhyAQ==
dependencies:
commander "^8.3.0"
@@ -5280,13 +5319,6 @@ loose-envify@^1.1.0, loose-envify@^1.4.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
-lower-case@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
- integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
- dependencies:
- tslib "^2.0.3"
-
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@@ -5370,9 +5402,9 @@ markdown-it-sup@^1.0.0:
integrity sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==
markdown-it@^13.0.1:
- version "13.0.1"
- resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430"
- integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==
+ version "13.0.2"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.2.tgz#1bc22e23379a6952e5d56217fbed881e0c94d536"
+ integrity sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==
dependencies:
argparse "^2.0.1"
entities "~3.0.1"
@@ -5846,6 +5878,11 @@ mockdate@^3.0.5:
resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb"
integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==
+monaco-editor@^0.43.0:
+ version "0.43.0"
+ resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.43.0.tgz#cb02a8d23d1249ad00b7cffe8bbecc2ac09d4baf"
+ integrity sha512-cnoqwQi/9fml2Szamv1XbSJieGJ1Dc8tENVMD26Kcfl7xGQWp7OBKMjlwKVGYFJ3/AXJjSOGvcqK7Ry/j9BM1Q==
+
morgan@^1.6.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7"
@@ -5957,14 +5994,6 @@ next-tick@^1.1.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
-no-case@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
- integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
- dependencies:
- lower-case "^2.0.2"
- tslib "^2.0.3"
-
node-environment-flags@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
@@ -6339,19 +6368,19 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-pac-proxy-agent@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz#db42120c64292685dafaf2bd921e223c56bfb13b"
- integrity sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA==
+pac-proxy-agent@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz#6b9ddc002ec3ff0ba5fdf4a8a21d363bcc612d75"
+ integrity sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==
dependencies:
"@tootallnate/quickjs-emscripten" "^0.23.0"
agent-base "^7.0.2"
debug "^4.3.4"
get-uri "^6.0.1"
http-proxy-agent "^7.0.0"
- https-proxy-agent "^7.0.0"
+ https-proxy-agent "^7.0.2"
pac-resolver "^7.0.0"
- socks-proxy-agent "^8.0.1"
+ socks-proxy-agent "^8.0.2"
pac-resolver@^7.0.0:
version "7.0.0"
@@ -6711,9 +6740,9 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8, postcss@^8.4.21, postcss@^8.4.23:
- version "8.4.29"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd"
- integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==
+ version "8.4.30"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7"
+ integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
@@ -6761,19 +6790,19 @@ prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.13.1"
-proxy-agent@6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.0.tgz#72f7bb20eb06049db79f7f86c49342c34f9ba08d"
- integrity sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==
+proxy-agent@6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.1.tgz#40e7b230552cf44fd23ffaf7c59024b692612687"
+ integrity sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==
dependencies:
agent-base "^7.0.2"
debug "^4.3.4"
http-proxy-agent "^7.0.0"
- https-proxy-agent "^7.0.0"
+ https-proxy-agent "^7.0.2"
lru-cache "^7.14.1"
- pac-proxy-agent "^7.0.0"
+ pac-proxy-agent "^7.0.1"
proxy-from-env "^1.1.0"
- socks-proxy-agent "^8.0.1"
+ socks-proxy-agent "^8.0.2"
proxy-from-env@^1.1.0:
version "1.1.0"
@@ -6821,16 +6850,16 @@ punycode@^2.1.0, punycode@^2.1.1:
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
puppeteer-core@^21.1.0:
- version "21.1.1"
- resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.1.1.tgz#59be20b6f69acc2139ba2d9e02a33793b59254ff"
- integrity sha512-Tlcajcf44zwfa9Sbwv3T8BtaNMJ69wtpHIxwl2NOBTyTK3D1wppQovXTjfw0TDOm3a16eCfQ+5BMi3vRQ4kuAQ==
+ version "21.3.5"
+ resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.3.5.tgz#f9f592590ce2c3633725ff4a6f924bc66c420640"
+ integrity sha512-C/yVgvob/HbUVTedhnURDruFkJYHEqJWlb6YltJGj/T7yzWdG4ouQ0JER8aX5g2RS4DMQ0xMNuhUVYMqC2QfnQ==
dependencies:
- "@puppeteer/browsers" "1.7.0"
- chromium-bidi "0.4.22"
+ "@puppeteer/browsers" "1.7.1"
+ chromium-bidi "0.4.28"
cross-fetch "4.0.0"
debug "4.3.4"
- devtools-protocol "0.0.1159816"
- ws "8.13.0"
+ devtools-protocol "0.0.1179426"
+ ws "8.14.2"
qiniu@^7.9.0:
version "7.9.0"
@@ -6972,6 +7001,11 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
+reading-time@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/reading-time/-/reading-time-1.5.0.tgz#d2a7f1b6057cb2e169beaf87113cc3411b5bc5bb"
+ integrity sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==
+
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@@ -7150,7 +7184,7 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
-resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.4.0:
+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.4.0:
version "1.22.4"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34"
integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==
@@ -7159,6 +7193,15 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
+resolve@^1.22.2:
+ version "1.22.6"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362"
+ integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@@ -7278,9 +7321,9 @@ safe-regex@^1.1.0:
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sax@^1.2.1, sax@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
- integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
+ integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
scheduler@^0.23.0:
version "0.23.0"
@@ -7398,9 +7441,9 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
simple-icons@^9.13.0:
- version "9.13.0"
- resolved "https://registry.yarnpkg.com/simple-icons/-/simple-icons-9.13.0.tgz#c91f161d0744d3328fb7459c8c785f0f8b83e418"
- integrity sha512-XpfRX8sX4kfizDW0SeD8ndy3twYndovdAmcIsJmJmwyLSOEP88emOVPBVj9zwb9apxRBqn+rHu4vMSPbbk8u5A==
+ version "9.16.0"
+ resolved "https://registry.yarnpkg.com/simple-icons/-/simple-icons-9.16.0.tgz#574ae8aa14d10451ad088c5578e26e8474402182"
+ integrity sha512-KM+7MWNlRnAjeURKV6VvJmjqfHuRLwgXxZ2IrtV+bqsz/8P/xmFEvJd+8xUww94bbPEIsHeXK7A9BwJASYnXrQ==
slash@^3.0.0:
version "3.0.0"
@@ -7427,14 +7470,6 @@ smart-buffer@^4.2.0:
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
-snake-case@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
- integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
- dependencies:
- dot-case "^3.0.4"
- tslib "^2.0.3"
-
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -7465,12 +7500,12 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
-socks-proxy-agent@^8.0.1:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz#ffc5859a66dac89b0c4dab90253b96705f3e7120"
- integrity sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==
+socks-proxy-agent@^8.0.2:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad"
+ integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==
dependencies:
- agent-base "^7.0.1"
+ agent-base "^7.0.2"
debug "^4.3.4"
socks "^2.7.1"
@@ -7607,6 +7642,11 @@ stack-trace@0.0.10:
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
+state-local@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
+ integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
+
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@@ -8128,16 +8168,11 @@ tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0:
+tslib@^2.0.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0, tslib@~2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
-tslib@~2.5.0:
- version "2.5.3"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913"
- integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==
-
tspan@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/tspan/-/tspan-0.4.0.tgz#49c2347598214443a77d7823e7c456e200a4aea2"
@@ -8188,9 +8223,9 @@ type-fest@^0.20.2:
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type-fest@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.3.1.tgz#5cb58cdab5120f7ab0b40cfdc35073fb9adb651d"
- integrity sha512-pphNW/msgOUSkJbH58x8sqpq8uQj6b0ZKGxEsLKMUnGorRcDjrUaLS+39+/ub41JNTwrrMyJcUB8+YZs3mbwqw==
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.3.2.tgz#bb7948127bb644364994dc1b44b8a797da8aadcd"
+ integrity sha512-VpwuOgnTsQUUWi0id8Hl4/xiQ+OoaeJGe8dnFjzubJYe/lOc2/d1Qx/d3FqWR0FlpOG/cvukAXfB12A49Y4iiA==
type-is@^1.6.16:
version "1.6.18"
@@ -8400,6 +8435,14 @@ update-browserslist-db@^1.0.11:
escalade "^3.1.1"
picocolors "^1.0.0"
+update-browserslist-db@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
+ integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
+
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
@@ -8437,6 +8480,11 @@ urllib@^2.34.1:
statuses "^1.3.1"
utility "^1.16.1"
+urlpattern-polyfill@9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz#bc7e386bb12fd7898b58d1509df21d3c29ab3460"
+ integrity sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==
+
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
@@ -8471,9 +8519,9 @@ uuid@^3.3.2:
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
- integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
+ integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
uvu@^0.5.0:
version "0.5.6"
@@ -8628,16 +8676,12 @@ vega-label@~1.2.1:
vega-util "^1.15.2"
vega-lite@^5.14.1:
- version "5.14.1"
- resolved "https://registry.yarnpkg.com/vega-lite/-/vega-lite-5.14.1.tgz#02177cb04af85c7011ab302a441d17e0bb6ac810"
- integrity sha512-VFvi0QtUoLQqwfAXTGjo0Acw/OTjiK3zOrcO/HyksGnnNDBHWM1GTcFryiWZYoAi99ehvv7tI/q94O46+fGRSQ==
- dependencies:
- "@types/clone" "~2.1.1"
- clone "~2.1.2"
- fast-deep-equal "~3.1.3"
- fast-json-stable-stringify "~2.1.0"
+ version "5.15.0"
+ resolved "https://registry.yarnpkg.com/vega-lite/-/vega-lite-5.15.0.tgz#aa339a0f66df2ef4b02e729f446a91b502f541e9"
+ integrity sha512-Eac4VBhdtwbJQWH8m2OaRba/YVZbUHlmTAiPfiF3XIapJ73rcs+gHZBE1DfYgfoGjBN+5YJUMvdgm4UE7j/Ncg==
+ dependencies:
json-stringify-pretty-compact "~3.0.0"
- tslib "~2.5.0"
+ tslib "~2.6.2"
vega-event-selector "~3.0.1"
vega-expression "~5.1.0"
vega-util "~1.17.2"
@@ -9111,10 +9155,10 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
-ws@8.13.0:
- version "8.13.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
- integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
+ws@8.14.2:
+ version "8.14.2"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f"
+ integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==
xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2"