├── .browserslistrc ├── dist ├── highlight.d.ts ├── env.d.ts ├── index.d.ts ├── types.d.ts ├── Code.vue.d.ts ├── hooks.d.ts ├── utils.d.ts ├── Line.vue.d.ts ├── Diff.vue.d.ts ├── index.css └── index.umd.js ├── dev ├── shims-vue.d.ts ├── main.ts ├── template.ts └── App.vue ├── tsconfig.node.json ├── .prettierrc ├── vite.config.docs.ts ├── src ├── env.d.ts ├── index.ts ├── types.ts ├── highlight.ts ├── Code.vue ├── Diff.vue ├── style.scss ├── hooks.ts ├── Line.vue └── utils.ts ├── .npmignore ├── .eslintrc.js ├── .gitignore ├── tsconfig.json ├── .github └── workflows │ ├── test.yaml │ └── release.yaml ├── vite.config.ts ├── LICENSE ├── index.html ├── __tests__ ├── index.spec.ts └── utils.spec.ts ├── package.json └── README.md /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | IE >= 11 4 | not dead 5 | -------------------------------------------------------------------------------- /dist/highlight.d.ts: -------------------------------------------------------------------------------- 1 | import hljs from 'highlight.js/lib/core'; 2 | export default hljs; 3 | -------------------------------------------------------------------------------- /dev/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | const component: DefineComponent<{}, {}, any>; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "trailingComma": "all", 7 | "printWidth": 80, 8 | "arrowParens": "avoid", 9 | "endOfLine": "auto" 10 | } 11 | -------------------------------------------------------------------------------- /vite.config.docs.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | base: '/vue-diff/', 7 | build: { 8 | outDir: 'docs', 9 | assetsDir: './', 10 | }, 11 | plugins: [vue()], 12 | }); 13 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue'; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | -------------------------------------------------------------------------------- /dist/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue'; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | ._* 3 | .DS_Store 4 | .git 5 | .hg 6 | .npmrc 7 | .lock-wscript 8 | .svn 9 | .wafpickle-* 10 | config.gypi 11 | CVS 12 | npm-debug.log 13 | 14 | /__tests__ 15 | /.github 16 | /demo 17 | /dev 18 | /node_modules 19 | .*rc 20 | .*rc.* 21 | .*ignore 22 | *config 23 | *config.* 24 | *.config.* 25 | index.html -------------------------------------------------------------------------------- /dev/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import VueDiff from '../src'; 4 | 5 | // extend yaml language 6 | import yaml from 'highlight.js/lib/languages/yaml'; 7 | 8 | VueDiff.hljs.registerLanguage('yaml', yaml); 9 | 10 | const app = createApp(App); 11 | app.use(VueDiff); 12 | app.mount('#app'); 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: ['plugin:vue/essential', 'standard', 'plugin:prettier/recommended'], 7 | parserOptions: { 8 | ecmaVersion: 12, 9 | parser: '@typescript-eslint/parser', 10 | sourceType: 'module', 11 | }, 12 | plugins: ['vue', '@typescript-eslint'], 13 | rules: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import Diff from './Diff.vue'; 3 | import type { App } from 'vue'; 4 | declare module '@vue/runtime-core' { 5 | interface GlobalComponents { 6 | Diff: typeof Diff; 7 | } 8 | } 9 | declare const _default: { 10 | install: (app: App, options?: {}) => void; 11 | hljs: import("highlight.js").HLJSApi; 12 | }; 13 | export default _default; 14 | export { Diff }; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /docs 5 | 6 | /tests/e2e/videos/ 7 | /tests/e2e/screenshots/ 8 | 9 | 10 | # local env files 11 | .env.local 12 | .env.*.local 13 | 14 | # Log files 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | pnpm-debug.log* 19 | 20 | # Editor directories and files 21 | .idea 22 | .vscode 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | 29 | # ignore 30 | /demo 31 | /dist -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import Diff from './Diff.vue'; 2 | import hljs from './highlight'; 3 | import './style.scss'; 4 | 5 | import type { App } from 'vue'; 6 | import type { PluginOptions } from './types'; 7 | 8 | declare module '@vue/runtime-core' { 9 | export interface GlobalComponents { 10 | Diff: typeof Diff; 11 | } 12 | } 13 | 14 | export default { 15 | install: (app: App, options = {}) => { 16 | const { componentName = 'Diff' } = options as PluginOptions; 17 | 18 | app.component(componentName, Diff); 19 | }, 20 | hljs, 21 | }; 22 | 23 | export { Diff } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "useDefineForClassFields": true, 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "lib": ["esnext", "dom"], 14 | "skipLibCheck": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "@/*": [ 18 | "src/*" 19 | ] 20 | }, 21 | }, 22 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "__tests__ /**/*.ts"], 23 | "references": [{ "path": "./tsconfig.node.json" }] 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - '*' 6 | - '*/*' 7 | - '**' 8 | - '!main' 9 | jobs: 10 | test: 11 | name: test 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | - name: Setup Node.js 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: 16 22 | - name: Install 23 | uses: borales/actions-yarn@v3.0.0 24 | with: 25 | cmd: install 26 | - name: Lint 27 | uses: borales/actions-yarn@v3.0.0 28 | with: 29 | cmd: eslint 30 | - name: Test 31 | uses: borales/actions-yarn@v3.0.0 32 | with: 33 | cmd: test 34 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { Diff } from 'diff-match-patch'; 2 | 3 | export interface PluginOptions { 4 | componentName: string; 5 | } 6 | 7 | export type Mode = 'split' | 'unified'; 8 | export type Theme = 'dark' | 'light' | `custom${string}`; 9 | export type Role = 'prev' | 'current' | 'unified'; 10 | 11 | export interface Line { 12 | type?: string; 13 | lineNum?: number; 14 | value?: string; 15 | chkWords?: boolean; 16 | [key: string]: unknown; 17 | } 18 | 19 | export type Lines = Array; 20 | export type Diffs = Array; 21 | 22 | export interface Meta { 23 | index: number; 24 | foldable: boolean; 25 | visible: boolean; 26 | top?: number; 27 | height?: number; 28 | } 29 | 30 | export interface VirtualScroll { 31 | height: number; 32 | lineMinHeight: number; 33 | delay: number; 34 | } 35 | -------------------------------------------------------------------------------- /src/highlight.ts: -------------------------------------------------------------------------------- 1 | import hljs from 'highlight.js/lib/core'; 2 | import css from 'highlight.js/lib/languages/css'; 3 | import xml from 'highlight.js/lib/languages/xml'; 4 | import markdown from 'highlight.js/lib/languages/markdown'; 5 | import javascript from 'highlight.js/lib/languages/javascript'; 6 | import json from 'highlight.js/lib/languages/json'; 7 | import plaintext from 'highlight.js/lib/languages/plaintext'; 8 | import typescript from 'highlight.js/lib/languages/typescript'; 9 | 10 | hljs.registerLanguage('css', css); 11 | hljs.registerLanguage('xml', xml); 12 | hljs.registerLanguage('markdown', markdown); 13 | hljs.registerLanguage('javascript', javascript); 14 | hljs.registerLanguage('json', json); 15 | hljs.registerLanguage('plaintext', plaintext); 16 | hljs.registerLanguage('typescript', typescript); 17 | 18 | export default hljs; 19 | -------------------------------------------------------------------------------- /dist/types.d.ts: -------------------------------------------------------------------------------- 1 | import type { Diff } from 'diff-match-patch'; 2 | export interface PluginOptions { 3 | componentName: string; 4 | } 5 | export declare type Mode = 'split' | 'unified'; 6 | export declare type Theme = 'dark' | 'light' | `custom${string}`; 7 | export declare type Role = 'prev' | 'current' | 'unified'; 8 | export interface Line { 9 | type?: string; 10 | lineNum?: number; 11 | value?: string; 12 | chkWords?: boolean; 13 | [key: string]: unknown; 14 | } 15 | export declare type Lines = Array; 16 | export declare type Diffs = Array; 17 | export interface Meta { 18 | index: number; 19 | foldable: boolean; 20 | visible: boolean; 21 | top?: number; 22 | height?: number; 23 | } 24 | export interface VirtualScroll { 25 | height: number; 26 | lineMinHeight: number; 27 | delay: number; 28 | } 29 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | const path = require('path'); 3 | import { defineConfig } from 'vite'; 4 | import vue from '@vitejs/plugin-vue'; 5 | import dts from 'vite-plugin-dts'; 6 | import { terser } from 'rollup-plugin-terser'; 7 | 8 | export default defineConfig({ 9 | build: { 10 | lib: { 11 | entry: path.resolve(__dirname, 'src/index.ts'), 12 | name: 'vue-diff', 13 | fileName: format => `index.${format}.js`, 14 | }, 15 | rollupOptions: { 16 | external: ['vue'], 17 | output: { 18 | globals: { 19 | vue: 'Vue', 20 | }, 21 | assetFileNames: assetInfo => { 22 | if (assetInfo.name == 'style.css') return 'index.css'; 23 | return assetInfo.name; 24 | }, 25 | }, 26 | plugins: [ 27 | terser({ 28 | compress: { 29 | defaults: false, 30 | drop_console: true, 31 | }, 32 | }), 33 | ], 34 | }, 35 | }, 36 | plugins: [vue(), dts()], 37 | test: { 38 | environment: 'jsdom', 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 hoiheart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | release: 8 | name: release 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - name: Setup Node.js 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: 16 19 | - name: Install 20 | uses: borales/actions-yarn@v3.0.0 21 | with: 22 | cmd: install 23 | - name: Build 24 | uses: borales/actions-yarn@v3.0.0 25 | with: 26 | cmd: build 27 | - name: Predeploy 28 | uses: borales/actions-yarn@v3.0.0 29 | with: 30 | cmd: predeploy 31 | - name: Deploy 32 | uses: peaceiris/actions-gh-pages@v3 33 | with: 34 | github_token: ${{ secrets.GITHUB_TOKEN }} 35 | publish_dir: ./docs 36 | - name: Release 37 | uses: cycjimmy/semantic-release-action@v2 38 | with: 39 | extra_plugins: | 40 | @semantic-release/git 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 44 | -------------------------------------------------------------------------------- /dist/Code.vue.d.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from 'vue'; 2 | import type { VirtualScroll } from './types'; 3 | declare const _sfc_main: import("vue").DefineComponent<{ 4 | language: { 5 | type: StringConstructor; 6 | required: true; 7 | }; 8 | code: { 9 | type: StringConstructor; 10 | required: true; 11 | }; 12 | scrollOptions: { 13 | type: PropType; 14 | default: boolean; 15 | }; 16 | }, { 17 | highlightCode: import("vue").Ref; 18 | }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "rendered"[], "rendered", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly; 29 | default: boolean; 30 | }; 31 | }>> & { 32 | onRendered?: ((...args: any[]) => any) | undefined; 33 | }, { 34 | scrollOptions: false | VirtualScroll; 35 | }>; 36 | export default _sfc_main; 37 | -------------------------------------------------------------------------------- /dist/hooks.d.ts: -------------------------------------------------------------------------------- 1 | import type { ComputedRef, Ref } from 'vue'; 2 | import type { Mode, Theme, Meta, VirtualScroll } from './types'; 3 | interface Props { 4 | mode: Mode; 5 | theme: Theme; 6 | language: string; 7 | prev: string; 8 | current: string; 9 | folding: boolean; 10 | inputDelay: number; 11 | virtualScroll: boolean | VirtualScroll; 12 | } 13 | export declare const useRender: (props: Props, viewer: Ref, scrollOptions: ComputedRef) => { 14 | meta: Ref<{ 15 | index: number; 16 | foldable: boolean; 17 | visible: boolean; 18 | top?: number | undefined; 19 | height?: number | undefined; 20 | }[]>; 21 | render: Ref<{ 22 | [x: string]: unknown; 23 | type?: string | undefined; 24 | lineNum?: number | undefined; 25 | value?: string | undefined; 26 | chkWords?: boolean | undefined; 27 | }[][]>; 28 | list: ComputedRef<{ 29 | index: number; 30 | foldable: boolean; 31 | visible: boolean; 32 | top?: number | undefined; 33 | height?: number | undefined; 34 | }[]>; 35 | }; 36 | export declare const useVirtualScroll: (props: Props, viewer: Ref, scrollOptions: ComputedRef, meta: Ref>) => { 37 | minHeight: ComputedRef; 38 | }; 39 | export {}; 40 | -------------------------------------------------------------------------------- /src/Code.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 61 | -------------------------------------------------------------------------------- /dist/utils.d.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue'; 2 | import type { Diffs, Lines, Mode } from './types'; 3 | declare const MODIFIED_START_TAG = ""; 4 | declare const MODIFIED_CLOSE_TAG = ""; 5 | declare enum DiffType { 6 | removed = -1, 7 | equal = 0, 8 | added = 1, 9 | disabled = 2 10 | } 11 | /** 12 | * Get diff type 13 | * @param diff 14 | */ 15 | declare const getDiffType: (type: DiffType) => string; 16 | /** 17 | * Get lines object on the split mode 18 | * @param diffsMap 19 | */ 20 | declare const getSplitLines: (diffsMap: Array) => Array; 21 | /** 22 | * Get lines object on the unified mode 23 | * @param diffsMap 24 | */ 25 | declare const getUnifiedLines: (diffsMap: Array) => Array; 26 | /** 27 | * Render of objects separated by lines 28 | * @param mode 29 | * @param prev 30 | * @param current 31 | */ 32 | declare const renderLines: (mode: Mode, prev: string, current: string) => Array; 33 | /** 34 | * Render with modified tags 35 | * @param prev 36 | * @param current 37 | */ 38 | declare const renderWords: (prev: string, current: string) => string; 39 | /** 40 | * Set hightlight code 41 | * This function must calling at client only (use DOM) 42 | */ 43 | declare const setHighlightCode: ({ highlightCode, language, code, }: { 44 | highlightCode: Ref; 45 | language: string; 46 | code: string; 47 | }) => void; 48 | export { MODIFIED_START_TAG, MODIFIED_CLOSE_TAG, getDiffType, getSplitLines, getUnifiedLines, renderLines, renderWords, setHighlightCode, }; 49 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue Diff 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

Vue Diff

18 | 19 | 20 | Star 21 | 22 |
23 |
24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | import { mount } from '@vue/test-utils'; 3 | import VueDiff from '../src/index'; 4 | 5 | describe('Plugin and component', () => { 6 | it('Install plugin', () => { 7 | const wrapper = mount( 8 | { 9 | template: ` 10 | 11 | `, 12 | }, 13 | { 14 | global: { 15 | plugins: [[VueDiff]], 16 | }, 17 | }, 18 | ); 19 | expect(wrapper.find('.vue-diff-wrapper')).toBeTruthy(); 20 | expect(wrapper.find('.vue-diff-mode-split')).toBeTruthy(); 21 | expect(wrapper.find('.vue-diff-theme-dark')).toBeTruthy(); 22 | }); 23 | 24 | it('Set plugin options', () => { 25 | const wrapper = mount( 26 | { 27 | template: ` 28 | 29 | `, 30 | }, 31 | { 32 | global: { 33 | plugins: [ 34 | [ 35 | VueDiff, 36 | { 37 | componentName: 'VueDiff', 38 | }, 39 | ], 40 | ], 41 | }, 42 | }, 43 | ); 44 | expect(wrapper.find('.vue-diff-wrapper')).toBeTruthy(); 45 | expect(wrapper.find('.vue-diff-mode-split')).toBeTruthy(); 46 | expect(wrapper.find('.vue-diff-theme-dark')).toBeTruthy(); 47 | }); 48 | 49 | it('Set component property', () => { 50 | const wrapper = mount( 51 | { 52 | template: ` 53 | 57 | `, 58 | }, 59 | { 60 | global: { 61 | plugins: [[VueDiff]], 62 | }, 63 | }, 64 | ); 65 | expect(wrapper.find('.vue-diff-wrapper')).toBeTruthy(); 66 | expect(wrapper.find('.vue-diff-mode-unified')).toBeTruthy(); 67 | expect(wrapper.find('.vue-diff-theme-light')).toBeTruthy(); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /dist/Line.vue.d.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from 'vue'; 2 | import type { Meta, Mode, Lines, Line, VirtualScroll } from './types'; 3 | declare const _sfc_main: import("vue").DefineComponent<{ 4 | mode: { 5 | type: PropType; 6 | required: true; 7 | }; 8 | folding: { 9 | type: BooleanConstructor; 10 | default: boolean; 11 | }; 12 | language: { 13 | type: StringConstructor; 14 | required: true; 15 | }; 16 | meta: { 17 | type: PropType; 18 | required: true; 19 | }; 20 | render: { 21 | type: PropType; 22 | required: true; 23 | }; 24 | scrollOptions: { 25 | type: PropType; 26 | default: boolean; 27 | }; 28 | }, { 29 | line: import("vue").Ref; 30 | isFoldLine: import("vue").ComputedRef; 31 | rendered: () => void; 32 | rowStyle: import("vue").ComputedRef<{ 33 | readonly position: "absolute"; 34 | readonly left: 0; 35 | readonly top: 0; 36 | readonly transform: "translate3d(0, undefinedpx, 0)" | `translate3d(0, ${number}px, 0)`; 37 | readonly minHeight: string; 38 | } | undefined>; 39 | setCode: (line: Line, render?: Lines | undefined, index?: number | undefined) => string; 40 | }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly; 43 | required: true; 44 | }; 45 | folding: { 46 | type: BooleanConstructor; 47 | default: boolean; 48 | }; 49 | language: { 50 | type: StringConstructor; 51 | required: true; 52 | }; 53 | meta: { 54 | type: PropType; 55 | required: true; 56 | }; 57 | render: { 58 | type: PropType; 59 | required: true; 60 | }; 61 | scrollOptions: { 62 | type: PropType; 63 | default: boolean; 64 | }; 65 | }>>, { 66 | scrollOptions: false | VirtualScroll; 67 | folding: boolean; 68 | }>; 69 | export default _sfc_main; 70 | -------------------------------------------------------------------------------- /dev/template.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import jquery1 from './jquery-3.5.0.js?raw'; 3 | import jquery2 from './jquery-3.6.0.js?raw'; 4 | // @ts-check 5 | 6 | const javascript1 = `var a1 = { 7 | "name": "vue-diff", 8 | "version": "0.0.0", 9 | "description": "Vue diff viewer", 10 | "private": true, 11 | "peerDependencies": { 12 | "vue": "^3.0.0" 13 | } 14 | }`; 15 | 16 | const javascript2 = `const b2 = { 17 | "name": "vue-diff", 18 | "version": "1.0.0", 19 | "description": "Vue diff viewer", 20 | "scripts": { 21 | "test": "vue-cli-service test:unit" 22 | "lint": "vue-cli-service lint" 23 | }, 24 | "peerDependencies": { 25 | "vue": "^3.0.0" 26 | } 27 | }`; 28 | 29 | const html1 = ` 30 | 31 | 32 | 33 | 34 | Vue Diff 35 | 36 | 37 |
38 | 39 | 40 | `; 41 | 42 | const html2 = ` 43 | 44 | 45 | 46 | 47 | Vue Diff 48 | 49 | 50 | 51 |
52 | 53 | 54 | 55 | `; 56 | 57 | const css1 = `.vue-diff-wrapper { 58 | width: 100%; 59 | } 60 | 61 | .vue-diff-theme-dark { 62 | @import 'highlight.js/scss/vs2015.scss'; 63 | background-color: #000; 64 | } 65 | 66 | .vue-diff-theme-light { 67 | @import 'highlight.js/scss/vs.scss'; 68 | background-color: #fff; 69 | }`; 70 | 71 | const css2 = `.vue-diff-wrapper { 72 | overflow: hidden; 73 | width: 100%; 74 | border-radius: 0.3em; 75 | } 76 | 77 | .vue-diff-theme-dark { 78 | @import 'highlight.js/scss/monokai.scss'; 79 | background-color: #272822; 80 | } 81 | 82 | .vue-diff-theme-light { 83 | @import 'highlight.js/scss/vs.scss'; 84 | background-color: #fff; 85 | }`; 86 | 87 | const yaml1 = `name: Release 88 | 89 | on: 90 | push: 91 | branches: 92 | - alpha 93 | 94 | jobs: 95 | # job`; 96 | 97 | const yaml2 = `name: Release 98 | 99 | on: 100 | push: 101 | branches: 102 | - master 103 | 104 | jobs:`; 105 | 106 | export default { 107 | javascript1, 108 | javascript2, 109 | html1, 110 | html2, 111 | css1, 112 | css2, 113 | yaml1, 114 | yaml2, 115 | jquery1, 116 | jquery2, 117 | }; 118 | -------------------------------------------------------------------------------- /__tests__/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { nextTick } from 'vue'; 2 | import { describe, it, expect } from 'vitest'; 3 | import { ref } from 'vue'; 4 | import { 5 | MODIFIED_START_TAG, 6 | MODIFIED_CLOSE_TAG, 7 | getDiffType, 8 | getSplitLines, 9 | getUnifiedLines, 10 | renderLines, 11 | renderWords, 12 | setHighlightCode, 13 | } from '../src/utils'; 14 | 15 | import type { Diff } from 'diff-match-patch'; 16 | 17 | describe('Utils unit', () => { 18 | // diff-match-patch output 19 | const added: Diff = [1, '']; 20 | const removed: Diff = [-1, '']; 21 | const equal: Diff = [0, '']; 22 | // custom output 23 | const disabled: Diff = [2, '']; 24 | 25 | const prev: Diff = [-1, 'a\nb']; 26 | const curr: Diff = [1, 'c']; 27 | 28 | const diffsMap = [[prev, curr]]; 29 | 30 | it('getDiffType', () => { 31 | expect(getDiffType(added[0])).toBe('added'); 32 | expect(getDiffType(removed[0])).toBe('removed'); 33 | expect(getDiffType(equal[0])).toBe('equal'); 34 | expect(getDiffType(disabled[0])).toBe('disabled'); 35 | }); 36 | 37 | it('getSplitLines', () => { 38 | const result = getSplitLines(diffsMap); 39 | expect(result.length).toBe(2); 40 | expect(result[0][0].type).toBe('removed'); 41 | expect(result[0][0].lineNum).toBe(1); 42 | expect(result[0][0].value).toBe('a'); 43 | expect(result[0][0].chkWords).toBe(true); 44 | }); 45 | 46 | it('getUnifiedLines', () => { 47 | const result = getUnifiedLines(diffsMap); 48 | expect(result.length).toBe(3); 49 | expect(result[0][0].type).toBe('removed'); 50 | expect(result[0][0].lineNum).toBe(undefined); 51 | expect(result[0][0].value).toBe('a'); 52 | expect(result[1][0].type).toBe('removed'); 53 | expect(result[1][0].lineNum).toBe(undefined); 54 | expect(result[1][0].value).toBe('b'); 55 | expect(result[2][0].type).toBe('added'); 56 | expect(result[2][0].lineNum).toBe(1); 57 | expect(result[2][0].value).toBe('c'); 58 | }); 59 | 60 | it('getUnifiedLines', () => { 61 | const split = renderLines('split', prev[1], curr[1]); 62 | const unified = renderLines('unified', prev[1], curr[1]); 63 | expect(split.length).toBe(2); 64 | expect(unified.length).toBe(3); 65 | }); 66 | 67 | it('renderWords', () => { 68 | expect(renderWords('abc', 'abc')).toBe('abc'); 69 | expect(renderWords('abc', 'acc')).toBe( 70 | `a${MODIFIED_START_TAG}c${MODIFIED_CLOSE_TAG}c`, 71 | ); 72 | }); 73 | 74 | it('setHighlightCode', async () => { 75 | const highlightCode = ref(''); 76 | 77 | setHighlightCode({ 78 | highlightCode, 79 | language: 'plaintext', 80 | code: `a ${MODIFIED_START_TAG}c${MODIFIED_CLOSE_TAG} c`, 81 | }); 82 | 83 | expect(highlightCode.value).toBe('a c c'); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /src/Diff.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 110 | -------------------------------------------------------------------------------- /src/style.scss: -------------------------------------------------------------------------------- 1 | .vue-diff-wrapper { 2 | overflow: hidden; 3 | width: 100%; 4 | border-radius: 0.3em; 5 | } 6 | 7 | .vue-diff-theme-dark { 8 | @import 'highlight.js/scss/monokai.scss'; 9 | 10 | background-color: #272822; 11 | } 12 | 13 | .vue-diff-theme-light { 14 | @import 'highlight.js/scss/vs.scss'; 15 | 16 | background-color: #fff; 17 | } 18 | 19 | .vue-diff-viewer { 20 | overflow-y: auto; 21 | width: 100%; 22 | padding: 1em 0; 23 | line-height: 1.5; 24 | font-size: 16px; 25 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 26 | 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 27 | 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; 28 | text-align: left; 29 | 30 | .vue-diff-viewer-inner { 31 | position: relative; 32 | width: 100%; 33 | } 34 | 35 | .vue-diff-row { 36 | display: flex; 37 | width: 100%; 38 | 39 | > div { 40 | padding: 0 0.5em; 41 | box-sizing: border-box; 42 | } 43 | 44 | .lineNum { 45 | flex: 0 0 auto; 46 | width: 50px; 47 | padding-top: 0.05em; 48 | text-align: right; 49 | color: #999; 50 | font-size: 0.9em; 51 | } 52 | 53 | .code { 54 | width: calc(100% - 50px); 55 | } 56 | 57 | &.vue-diff-row-split .code { 58 | width: calc(50% - 50px); 59 | } 60 | 61 | .vue-diff-cell-removed { 62 | background-color: rgba(255, 0, 0, 0.1); 63 | 64 | span.modified { 65 | background-color: rgba(255, 0, 0, 0.15); 66 | } 67 | 68 | code::before { 69 | content: '-'; 70 | } 71 | } 72 | 73 | .vue-diff-cell-added { 74 | background-color: rgba(0, 255, 128, 0.1); 75 | 76 | span.modified { 77 | background-color: rgba(0, 255, 128, 0.15); 78 | } 79 | 80 | code:before { 81 | content: '+'; 82 | } 83 | } 84 | 85 | .vue-diff-cell-disabled { 86 | background-color: rgba(128, 128, 128, 0.1); 87 | } 88 | 89 | .vue-diff-cell-fold { 90 | &.lineNum { 91 | opacity: 0.8; 92 | font-size: 0.8em; 93 | 94 | &:before { 95 | content: '>'; 96 | } 97 | } 98 | 99 | &.code { 100 | text-align: center; 101 | 102 | &:before { 103 | color: #999; 104 | content: '⋯⋯'; 105 | } 106 | } 107 | } 108 | 109 | pre { 110 | display: block; 111 | position: relative; 112 | max-width: 100%; 113 | margin: 0; 114 | padding: 0; 115 | padding-left: 1.5em; 116 | overflow: visible; 117 | background: none; 118 | border-radius: 0; 119 | } 120 | 121 | .hljs { 122 | overflow: visible; 123 | padding: 0; 124 | background: transparent; 125 | word-wrap: break-all; 126 | word-break: break-all; 127 | white-space: pre-wrap; 128 | } 129 | 130 | code { 131 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 132 | 'Liberation Mono', 'Courier New', monospace; 133 | 134 | &::before { 135 | display: inline-block; 136 | position: absolute; 137 | left: 0; 138 | top: 0; 139 | opacity: 0.8; 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /dist/Diff.vue.d.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from 'vue'; 2 | import type { Mode, Theme, VirtualScroll } from './types'; 3 | declare const _sfc_main: import("vue").DefineComponent<{ 4 | mode: { 5 | type: PropType; 6 | default: string; 7 | }; 8 | theme: { 9 | type: PropType; 10 | default: string; 11 | }; 12 | language: { 13 | type: StringConstructor; 14 | default: string; 15 | }; 16 | prev: { 17 | type: StringConstructor; 18 | default: string; 19 | }; 20 | current: { 21 | type: StringConstructor; 22 | default: string; 23 | }; 24 | folding: { 25 | type: BooleanConstructor; 26 | default: boolean; 27 | }; 28 | inputDelay: { 29 | type: NumberConstructor; 30 | default: number; 31 | }; 32 | virtualScroll: { 33 | type: PropType; 34 | default: boolean; 35 | }; 36 | }, { 37 | list: import("vue").ComputedRef<{ 38 | index: number; 39 | foldable: boolean; 40 | visible: boolean; 41 | top?: number | undefined; 42 | height?: number | undefined; 43 | }[]>; 44 | meta: import("vue").Ref<{ 45 | index: number; 46 | foldable: boolean; 47 | visible: boolean; 48 | top?: number | undefined; 49 | height?: number | undefined; 50 | }[]>; 51 | minHeight: import("vue").ComputedRef; 52 | render: import("vue").Ref<{ 53 | [x: string]: unknown; 54 | type?: string | undefined; 55 | lineNum?: number | undefined; 56 | value?: string | undefined; 57 | chkWords?: boolean | undefined; 58 | }[][]>; 59 | scrollOptions: import("vue").ComputedRef; 64 | setLineHeight: (index: number, height: number) => void; 65 | viewer: import("vue").Ref; 66 | }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly; 69 | default: string; 70 | }; 71 | theme: { 72 | type: PropType; 73 | default: string; 74 | }; 75 | language: { 76 | type: StringConstructor; 77 | default: string; 78 | }; 79 | prev: { 80 | type: StringConstructor; 81 | default: string; 82 | }; 83 | current: { 84 | type: StringConstructor; 85 | default: string; 86 | }; 87 | folding: { 88 | type: BooleanConstructor; 89 | default: boolean; 90 | }; 91 | inputDelay: { 92 | type: NumberConstructor; 93 | default: number; 94 | }; 95 | virtualScroll: { 96 | type: PropType; 97 | default: boolean; 98 | }; 99 | }>>, { 100 | language: string; 101 | mode: Mode; 102 | folding: boolean; 103 | theme: Theme; 104 | prev: string; 105 | current: string; 106 | inputDelay: number; 107 | virtualScroll: boolean | VirtualScroll; 108 | }>; 109 | export default _sfc_main; 110 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-diff", 3 | "version": "1.2.4", 4 | "description": "Vue diff viewer", 5 | "license": "ISC", 6 | "author": { 7 | "name": "hoiheart", 8 | "email": "hoiheart@gmail.com", 9 | "url": "https://github.com/hoiheart" 10 | }, 11 | "keywords": [ 12 | "Vue", 13 | "VueJS", 14 | "Vue diff", 15 | "VueJS diff" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/hoiheart/vue-diff.git" 20 | }, 21 | "homepage": "https://github.com/hoiheart/vue-diff#readme", 22 | "bugs": { 23 | "url": "https://github.com/hoiheart/vue-diff/issues" 24 | }, 25 | "scripts": { 26 | "dev": "vite -c vite.config.docs.ts", 27 | "build": "vue-tsc --noEmit && vite build", 28 | "predeploy": "vite build -c vite.config.docs.ts", 29 | "deploy": "gh-pages -d docs -r origin", 30 | "test": "vitest --run" 31 | }, 32 | "main": "./dist/index.umd.js", 33 | "module": "./dist/index.es.js", 34 | "types": "./dist/index.d.ts", 35 | "dependencies": { 36 | "@vueuse/core": "^8.3.1", 37 | "diff-match-patch": "^1.0.5", 38 | "highlight.js": "^11.5.1" 39 | }, 40 | "devDependencies": { 41 | "@semantic-release/git": "^10.0.1", 42 | "@types/diff-match-patch": "^1.0.32", 43 | "@vitejs/plugin-vue": "^2.3.1", 44 | "@vue/test-utils": "^2.0.0-rc.21", 45 | "conventional-changelog-conventionalcommits": "^4.6.3", 46 | "eslint": "^8.14.0", 47 | "eslint-config-prettier": "^8.5.0", 48 | "eslint-plugin-vue": "^8.7.1", 49 | "gh-pages": "^3.2.3", 50 | "jsdom": "^19.0.0", 51 | "prettier": "2.6.2", 52 | "rollup-plugin-terser": "^7.0.2", 53 | "sass": "^1.50.1", 54 | "sass-loader": "^12.6.0", 55 | "typescript": "^4.6.3", 56 | "vite": "^2.9.5", 57 | "vite-plugin-dts": "^1.1.0", 58 | "vitest": "^0.9.4", 59 | "vue": "^3.2.25", 60 | "vue-tsc": "^0.34.7" 61 | }, 62 | "release": { 63 | "branches": [ 64 | "main" 65 | ], 66 | "plugins": [ 67 | [ 68 | "@semantic-release/commit-analyzer", 69 | { 70 | "releaseRules": [ 71 | { 72 | "type": "refactor", 73 | "release": "patch" 74 | }, 75 | { 76 | "type": "perf", 77 | "release": "patch" 78 | }, 79 | { 80 | "type": "docs", 81 | "release": "patch" 82 | }, 83 | { 84 | "type": "style", 85 | "release": "patch" 86 | }, 87 | { 88 | "type": "build", 89 | "release": "patch" 90 | } 91 | ] 92 | } 93 | ], 94 | [ 95 | "@semantic-release/release-notes-generator", 96 | { 97 | "preset": "conventionalcommits", 98 | "presetConfig": { 99 | "types": [ 100 | { 101 | "type": "feat", 102 | "section": "Features" 103 | }, 104 | { 105 | "type": "fix", 106 | "section": "Bug Fixes" 107 | }, 108 | { 109 | "type": "chore", 110 | "hidden": true 111 | }, 112 | { 113 | "type": "docs", 114 | "hidden": false, 115 | "section": "Docs" 116 | }, 117 | { 118 | "type": "style", 119 | "hidden": false, 120 | "section": "Style" 121 | }, 122 | { 123 | "type": "build", 124 | "hidden": false, 125 | "section": "Build" 126 | }, 127 | { 128 | "type": "refactor", 129 | "hidden": false, 130 | "section": "Refactor" 131 | }, 132 | { 133 | "type": "perf", 134 | "hidden": false, 135 | "section": "Perfomance" 136 | }, 137 | { 138 | "type": "test", 139 | "hidden": true 140 | } 141 | ] 142 | } 143 | } 144 | ], 145 | "@semantic-release/npm", 146 | [ 147 | "@semantic-release/git", 148 | { 149 | "assets": [ 150 | "dist", 151 | "demo", 152 | "package.json", 153 | "package-lock.json" 154 | ], 155 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 156 | } 157 | ], 158 | "@semantic-release/github" 159 | ] 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/hooks.ts: -------------------------------------------------------------------------------- 1 | import { 2 | computed, 3 | nextTick, 4 | onBeforeUnmount, 5 | onMounted, 6 | ref, 7 | watch, 8 | } from 'vue'; 9 | import { useThrottleFn, debouncedWatch } from '@vueuse/core'; 10 | import { renderLines } from './utils'; 11 | 12 | import type { ComputedRef, Ref } from 'vue'; 13 | import type { Mode, Theme, Meta, Lines, VirtualScroll } from './types'; 14 | 15 | interface Props { 16 | mode: Mode; 17 | theme: Theme; 18 | language: string; 19 | prev: string; 20 | current: string; 21 | folding: boolean; 22 | inputDelay: number; 23 | virtualScroll: boolean | VirtualScroll; 24 | } 25 | 26 | export const useRender = ( 27 | props: Props, 28 | viewer: Ref, 29 | scrollOptions: ComputedRef, 30 | ) => { 31 | const render = ref>([]); 32 | const meta = ref>([]); 33 | const list = computed(() => 34 | meta.value.filter(item => { 35 | return props.folding ? !item.foldable && item.visible : item.visible; 36 | }), 37 | ); 38 | 39 | const setRender = () => { 40 | const result = renderLines(props.mode, props.prev, props.current); 41 | render.value = result; 42 | meta.value.splice(render.value.length); 43 | 44 | render.value.map((v, index: number) => { 45 | const item = meta.value[index]; 46 | const foldable = 47 | props.folding && 48 | v[0].type === 'equal' && 49 | render.value[index - 1]?.[0].type === 'equal'; 50 | 51 | const values = { 52 | index, 53 | foldable, 54 | visible: true, 55 | }; 56 | 57 | if (scrollOptions.value) { 58 | meta.value[index] = { 59 | ...values, 60 | visible: item?.visible || false, 61 | top: item?.top || undefined, 62 | height: item?.height || scrollOptions.value.lineMinHeight, 63 | }; 64 | } else { 65 | meta.value[index] = { ...values }; 66 | } 67 | }); 68 | }; 69 | 70 | debouncedWatch( 71 | [ 72 | () => props.mode, 73 | () => props.prev, 74 | () => props.current, 75 | () => props.folding, 76 | ], 77 | setRender, 78 | { 79 | debounce: props.inputDelay, 80 | immediate: true, 81 | }, 82 | ); 83 | 84 | return { 85 | meta, 86 | render, 87 | list, 88 | }; 89 | }; 90 | 91 | export const useVirtualScroll = ( 92 | props: Props, 93 | viewer: Ref, 94 | scrollOptions: ComputedRef, 95 | meta: Ref>, 96 | ) => { 97 | const minHeight = computed(() => { 98 | if (!scrollOptions.value) return undefined; 99 | const reduce = meta.value.reduce((acc, curr) => { 100 | curr.top = acc; 101 | return curr.foldable ? acc : acc + (curr.height as number); 102 | }, 0); 103 | return reduce + 'px'; 104 | }); 105 | 106 | const setMeta = () => { 107 | if (!viewer.value || !scrollOptions.value) return; 108 | const scrollTop = viewer.value.scrollTop; 109 | const height = scrollOptions.value.height; 110 | const min = scrollTop - height * 1.5; 111 | const max = scrollTop + height + height * 1.5; 112 | 113 | meta.value.reduce((acc, curr) => { 114 | if (acc >= min && acc <= max) { 115 | curr.visible = true; 116 | } else { 117 | curr.visible = false; 118 | } 119 | 120 | curr.top = acc; 121 | return curr.foldable ? acc : acc + (curr.height as number); 122 | }, 0); 123 | }; 124 | 125 | debouncedWatch( 126 | [ 127 | () => props.mode, 128 | () => props.prev, 129 | () => props.current, 130 | () => props.folding, 131 | ], 132 | () => nextTick(setMeta), 133 | { 134 | debounce: props.inputDelay, 135 | immediate: true, 136 | }, 137 | ); 138 | 139 | onMounted(() => { 140 | if (!scrollOptions.value) return; 141 | viewer.value?.addEventListener( 142 | 'scroll', 143 | useThrottleFn(setMeta, scrollOptions.value.delay), 144 | ); 145 | }); 146 | 147 | onBeforeUnmount(() => { 148 | if (!scrollOptions.value) return; 149 | viewer.value?.removeEventListener( 150 | 'scroll', 151 | useThrottleFn(setMeta, scrollOptions.value.delay), 152 | ); 153 | }); 154 | 155 | watch(scrollOptions, (val, prev) => { 156 | if (!prev && val) { 157 | viewer.value?.addEventListener( 158 | 'scroll', 159 | useThrottleFn(setMeta, val.delay), 160 | ); 161 | } 162 | if (prev && !val) { 163 | viewer.value?.removeEventListener( 164 | 'scroll', 165 | useThrottleFn(setMeta, prev.delay), 166 | ); 167 | } 168 | }); 169 | 170 | return { 171 | minHeight, 172 | }; 173 | }; 174 | -------------------------------------------------------------------------------- /src/Line.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 149 | -------------------------------------------------------------------------------- /dist/index.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";.vue-diff-wrapper{overflow:hidden;width:100%;border-radius:.3em}.vue-diff-theme-dark{background-color:#272822}.vue-diff-theme-dark pre code.hljs{display:block;overflow-x:auto;padding:1em}.vue-diff-theme-dark code.hljs{padding:3px 5px}.vue-diff-theme-dark .hljs{background:#272822;color:#ddd}.vue-diff-theme-dark .hljs-keyword,.vue-diff-theme-dark .hljs-literal,.vue-diff-theme-dark .hljs-name,.vue-diff-theme-dark .hljs-selector-tag,.vue-diff-theme-dark .hljs-strong,.vue-diff-theme-dark .hljs-tag{color:#f92672}.vue-diff-theme-dark .hljs-code{color:#66d9ef}.vue-diff-theme-dark .hljs-attribute,.vue-diff-theme-dark .hljs-link,.vue-diff-theme-dark .hljs-regexp,.vue-diff-theme-dark .hljs-symbol{color:#bf79db}.vue-diff-theme-dark .hljs-addition,.vue-diff-theme-dark .hljs-built_in,.vue-diff-theme-dark .hljs-bullet,.vue-diff-theme-dark .hljs-emphasis,.vue-diff-theme-dark .hljs-section,.vue-diff-theme-dark .hljs-selector-attr,.vue-diff-theme-dark .hljs-selector-pseudo,.vue-diff-theme-dark .hljs-string,.vue-diff-theme-dark .hljs-subst,.vue-diff-theme-dark .hljs-template-tag,.vue-diff-theme-dark .hljs-template-variable,.vue-diff-theme-dark .hljs-title,.vue-diff-theme-dark .hljs-type,.vue-diff-theme-dark .hljs-variable{color:#a6e22e}.vue-diff-theme-dark .hljs-class .hljs-title,.vue-diff-theme-dark .hljs-title.class_{color:#fff}.vue-diff-theme-dark .hljs-comment,.vue-diff-theme-dark .hljs-deletion,.vue-diff-theme-dark .hljs-meta,.vue-diff-theme-dark .hljs-quote{color:#75715e}.vue-diff-theme-dark .hljs-doctag,.vue-diff-theme-dark .hljs-keyword,.vue-diff-theme-dark .hljs-literal,.vue-diff-theme-dark .hljs-section,.vue-diff-theme-dark .hljs-selector-id,.vue-diff-theme-dark .hljs-selector-tag,.vue-diff-theme-dark .hljs-title,.vue-diff-theme-dark .hljs-type{font-weight:700}.vue-diff-theme-light{background-color:#fff}.vue-diff-theme-light pre code.hljs{display:block;overflow-x:auto;padding:1em}.vue-diff-theme-light code.hljs{padding:3px 5px}.vue-diff-theme-light .hljs{background:#fff;color:#000}.vue-diff-theme-light .hljs-comment,.vue-diff-theme-light .hljs-quote,.vue-diff-theme-light .hljs-variable{color:green}.vue-diff-theme-light .hljs-built_in,.vue-diff-theme-light .hljs-keyword,.vue-diff-theme-light .hljs-name,.vue-diff-theme-light .hljs-selector-tag,.vue-diff-theme-light .hljs-tag{color:#00f}.vue-diff-theme-light .hljs-addition,.vue-diff-theme-light .hljs-attribute,.vue-diff-theme-light .hljs-literal,.vue-diff-theme-light .hljs-section,.vue-diff-theme-light .hljs-string,.vue-diff-theme-light .hljs-template-tag,.vue-diff-theme-light .hljs-template-variable,.vue-diff-theme-light .hljs-title,.vue-diff-theme-light .hljs-type{color:#a31515}.vue-diff-theme-light .hljs-deletion,.vue-diff-theme-light .hljs-meta,.vue-diff-theme-light .hljs-selector-attr,.vue-diff-theme-light .hljs-selector-pseudo{color:#2b91af}.vue-diff-theme-light .hljs-doctag{color:gray}.vue-diff-theme-light .hljs-attr{color:red}.vue-diff-theme-light .hljs-bullet,.vue-diff-theme-light .hljs-link,.vue-diff-theme-light .hljs-symbol{color:#00b0e8}.vue-diff-theme-light .hljs-emphasis{font-style:italic}.vue-diff-theme-light .hljs-strong{font-weight:700}.vue-diff-viewer{overflow-y:auto;width:100%;padding:1em 0;line-height:1.5;font-size:16px;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";text-align:left}.vue-diff-viewer .vue-diff-viewer-inner{position:relative;width:100%}.vue-diff-viewer .vue-diff-row{display:flex;width:100%}.vue-diff-viewer .vue-diff-row>div{padding:0 .5em;box-sizing:border-box}.vue-diff-viewer .vue-diff-row .lineNum{flex:0 0 auto;width:50px;padding-top:.05em;text-align:right;color:#999;font-size:.9em}.vue-diff-viewer .vue-diff-row .code{width:calc(100% - 50px)}.vue-diff-viewer .vue-diff-row.vue-diff-row-split .code{width:calc(50% - 50px)}.vue-diff-viewer .vue-diff-row .vue-diff-cell-removed{background-color:#ff00001a}.vue-diff-viewer .vue-diff-row .vue-diff-cell-removed span.modified{background-color:#ff000026}.vue-diff-viewer .vue-diff-row .vue-diff-cell-removed code:before{content:"-"}.vue-diff-viewer .vue-diff-row .vue-diff-cell-added{background-color:#00ff801a}.vue-diff-viewer .vue-diff-row .vue-diff-cell-added span.modified{background-color:#00ff8026}.vue-diff-viewer .vue-diff-row .vue-diff-cell-added code:before{content:"+"}.vue-diff-viewer .vue-diff-row .vue-diff-cell-disabled{background-color:#8080801a}.vue-diff-viewer .vue-diff-row .vue-diff-cell-fold.lineNum{opacity:.8;font-size:.8em}.vue-diff-viewer .vue-diff-row .vue-diff-cell-fold.lineNum:before{content:">"}.vue-diff-viewer .vue-diff-row .vue-diff-cell-fold.code{text-align:center}.vue-diff-viewer .vue-diff-row .vue-diff-cell-fold.code:before{color:#999;content:"\22ef\22ef"}.vue-diff-viewer .vue-diff-row pre{display:block;position:relative;max-width:100%;margin:0;padding:0 0 0 1.5em;overflow:visible;background:none;border-radius:0}.vue-diff-viewer .vue-diff-row .hljs{overflow:visible;padding:0;background:transparent;word-wrap:break-all;word-break:break-all;white-space:pre-wrap}.vue-diff-viewer .vue-diff-row code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.vue-diff-viewer .vue-diff-row code:before{display:inline-block;position:absolute;left:0;top:0;opacity:.8} 2 | -------------------------------------------------------------------------------- /dev/App.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 177 | 178 | 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-diff 2 | 3 | Vue diff viewer plugin for Vue@3 4 | demo 5 | 6 | ## Table of Contents 7 | 8 | - [Table of Contents](#table-of-contents) 9 | - [Introduction](#introduction) 10 | - [Features](#features) 11 | - [Install plugin](#install-plugin) 12 | - [Options](#options) 13 | - [Usage diff viewer](#usage-diff-viewer) 14 | - [Settings with default props](#settings-with-default-props) 15 | - [Settings with full props](#settings-with-full-props) 16 | - [Props](#props) 17 | - [Custom theme](#custom-theme) 18 | - [Extend languages](#extend-languages) 19 | - [Default supported languages and values](#default-supported-languages-and-values) 20 | - [Virtual scroll](#virtual-scroll) 21 | - [Object props](#object-props) 22 | 23 | ## Introduction 24 | 25 | screenshot 26 | 27 | You can see the difference between the two codes with the `vue-diff` plugin. 28 | This plugin dependent on diff-match-patch and highlight.js, shows similar results to other diff viewers (e.g., Github Desktop). 29 | Here is the demo 30 | 31 | ## Features 32 | 33 | - Support split / unified mode 34 | - Support multiple languages and can be extended 35 | - Support two themes (dark / light) and can be customized 36 | - Virtual scroll for large text comparison 37 | - Folding view (_Partial folding is not supported_) 38 | - Support typescript 39 | 40 | ## Install plugin 41 | 42 | ```bash 43 | npm install vue-diff 44 | ``` 45 | 46 | And install plugin in vue application 47 | 48 | ```ts 49 | import VueDiff from 'vue-diff'; 50 | 51 | import 'vue-diff/dist/index.css'; 52 | 53 | app.use(VueDiff); 54 | ``` 55 | 56 | ### Options 57 | 58 | ```ts 59 | app.use(VueDiff, { 60 | componentName: 'VueDiff', 61 | }); 62 | ``` 63 | 64 | | name | type | detault | description | 65 | | ------------- | -------- | ------- | -------------------------- | 66 | | componentName | `string` | `Diff` | Global diff component name | 67 | 68 | ## Usage diff viewer 69 | 70 | Insert the diff component with props. 71 | 72 | ### Settings with default props 73 | 74 | ```vue 75 | 87 | ``` 88 | 89 | ### Settings with full props 90 | 91 | ```vue 92 | 104 | ``` 105 | 106 | ### Props 107 | 108 | | name | type | detault | values | description | 109 | | ------------- | ----------------- | ----------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | 110 | | mode | `string` | `split` | `split`, `unified` | 111 | | theme | `string` | `dark` | `dark`, `light`, `custom${string}` | See Custom theme | 112 | | language | `string` | `plaintext` | | See Extend languages | 113 | | prev | `string` | `''` | | Prev code | 114 | | current | `string` | `''` | | Current Code | 115 | | folding | `boolean` | `false` | | Folding not different | 116 | | inputDelay | `number` | `0` | | Setting up rendering debounce for changes for performance benefit (mode, prev, curr) | 117 | | virtualScroll | `boolean\|object` | `false` | | _Default value when setting true :_
`{ height: 500, lineMinHeight: 24, delay: 100 }`
See virtual scroll | 118 | 119 | ## Custom theme 120 | 121 | `vue-diff` uses the following highlight.js themes and can be customized. 122 | 123 | - dark: `highlight.js/scss/monokai.scss` 124 | - light: `highlight.js/scss/vs.scss` 125 | 126 | ```bash 127 | npm install highlight.js 128 | ``` 129 | 130 | ```vue 131 | 141 | 142 | 149 | ``` 150 | 151 | ## Extend languages 152 | 153 | `vue-diff` supports the following languages and can be extended through highlight.js language registration. 154 | 155 | ### Default supported languages and values 156 | 157 | - `css` 158 | - `xml`: `xml`, `html`, `xhtml`, `rss`, `atom`, `xjb`, `xsd`, `xsl`, `plist`, `svg` 159 | - `markdown`: `markdown`, `md`, `mkdown`, `mkd` 160 | - `javascript`: `javascript`, `js`, `jsx` 161 | - `json` 162 | - `plaintext`: `plaintext`, `txt`, `text` 163 | - `typescript`: `typescript`, `ts` 164 | 165 | ```bash 166 | npm install highlight.js 167 | ``` 168 | 169 | ```ts 170 | import VueDiff from 'vue-diff'; 171 | import 'vue-diff/dist/index.css'; 172 | 173 | // extend yaml language 174 | import yaml from 'highlight.js/lib/languages/yaml'; 175 | 176 | VueDiff.hljs.registerLanguage('yaml', yaml); 177 | 178 | app.use(VueDiff); 179 | ``` 180 | 181 | > Check supported languages of Highlight.js 182 | 183 | ## Virtual scroll 184 | 185 | Comparing text from many lines can slow down performance.
186 | With virtualScroll props, virtualScroll applies. (Self-made for this plug-in.) 187 | 188 | #### Object property value 189 | 190 | When using virtual scroll, the css of all code lines is changed to the absolute position, which requires detailed settings. 191 | 192 | - height (`number`): Diff box height (Applies only to px values) 193 | - lineMinHeight (`number`): minimum height of line 194 | > Minimum height value of line is required for visible area calculation.
The default is 24, but you can set it yourself if you need to adjust it according to the page's front-size, line-height, etc. 195 | - delay (`number`): re-rendering delay when scrolling or resizing 196 | > Performance problems occur when too often a re-rendering function is invoked based on scrolling or resizing
This setting applies a delay using throttle. 197 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { diff_match_patch as DiffMatchPatch } from 'diff-match-patch'; 2 | import hljs from './highlight'; 3 | 4 | import type { Ref } from 'vue'; 5 | import type { Diffs, Lines, Mode } from './types'; 6 | 7 | const MODIFIED_START_TAG = ''; 8 | const MODIFIED_CLOSE_TAG = ''; 9 | 10 | enum DiffType { 11 | removed = -1, 12 | equal = 0, 13 | added = 1, 14 | disabled = 2, 15 | } 16 | 17 | /** 18 | * Get diff type 19 | * @param diff 20 | */ 21 | const getDiffType = (type: DiffType) => { 22 | if (!DiffType[type]) return 'disabled'; 23 | return DiffType[type]; 24 | }; 25 | 26 | /** 27 | * Get lines object on the split mode 28 | * @param diffsMap 29 | */ 30 | const getSplitLines = (diffsMap: Array): Array => { 31 | const result: Array = []; // Array(0): prev, Array(1): current 32 | const lineNum = { 33 | prev: 0, 34 | current: 0, 35 | }; 36 | 37 | diffsMap.map(diffs => { 38 | const prevLines = diffs[0][1].replace(/\n$/, '').split('\n'); 39 | const currentLines = diffs[1][1].replace(/\n$/, '').split('\n'); 40 | const loopCount = Math.max(prevLines.length, currentLines.length); 41 | 42 | for (let i = 0; i < loopCount; i++) { 43 | const hasPrevLine = 44 | getDiffType(diffs[0][0]) !== 'disabled' && 45 | typeof prevLines[i] !== 'undefined'; 46 | const hasCurrentLine = 47 | getDiffType(diffs[1][0]) !== 'disabled' && 48 | typeof currentLines[i] !== 'undefined'; 49 | 50 | if (hasPrevLine) lineNum.prev = lineNum.prev + 1; 51 | if (hasCurrentLine) lineNum.current = lineNum.current + 1; 52 | 53 | const chkWords = Boolean( 54 | getDiffType(diffs[0][0]).match(/added|removed/) && 55 | getDiffType(diffs[1][0]).match(/added|removed/), 56 | ); 57 | 58 | result.push([ 59 | { 60 | type: hasPrevLine ? getDiffType(diffs[0][0]) : 'disabled', 61 | lineNum: hasPrevLine ? lineNum.prev : undefined, 62 | value: hasPrevLine ? prevLines[i] : undefined, 63 | chkWords, 64 | }, 65 | { 66 | type: hasCurrentLine ? getDiffType(diffs[1][0]) : 'disabled', 67 | lineNum: hasCurrentLine ? lineNum.current : undefined, 68 | value: hasCurrentLine ? currentLines[i] : undefined, 69 | chkWords, 70 | }, 71 | ]); 72 | } 73 | }); 74 | 75 | return result; 76 | }; 77 | 78 | /** 79 | * Get lines object on the unified mode 80 | * @param diffsMap 81 | */ 82 | const getUnifiedLines = (diffsMap: Array): Array => { 83 | const result: Array = []; // Array(0) 84 | let lineNum = 0; 85 | 86 | diffsMap.map(diffs => { 87 | const prevLines = diffs[0][1].replace(/\n$/, '').split('\n'); 88 | const currentLines = diffs[1][1].replace(/\n$/, '').split('\n'); 89 | 90 | prevLines.map(value => { 91 | const type = getDiffType(diffs[0][0]); 92 | 93 | if (type !== 'removed') return; 94 | 95 | result.push([ 96 | { 97 | type: getDiffType(diffs[0][0]), 98 | lineNum: undefined, 99 | value: value, 100 | }, 101 | ]); 102 | }); 103 | 104 | currentLines.map(value => { 105 | const type = getDiffType(diffs[1][0]); 106 | 107 | if (type === 'disabled') return; 108 | 109 | lineNum = lineNum + 1; 110 | 111 | result.push([ 112 | { 113 | type: getDiffType(diffs[1][0]), 114 | lineNum, 115 | value: value, 116 | }, 117 | ]); 118 | }); 119 | }); 120 | 121 | return result; 122 | }; 123 | 124 | /** 125 | * Render of objects separated by lines 126 | * @param mode 127 | * @param prev 128 | * @param current 129 | */ 130 | const renderLines = ( 131 | mode: Mode, 132 | prev: string, 133 | current: string, 134 | ): Array => { 135 | function diffLines(prev: string, current: string) { 136 | const dmp = new DiffMatchPatch(); 137 | const a = dmp.diff_linesToChars_(prev, current); 138 | const linePrev = a.chars1; 139 | const lineCurrent = a.chars2; 140 | const lineArray = a.lineArray; 141 | const diffs = dmp.diff_main(linePrev, lineCurrent, false); 142 | dmp.diff_charsToLines_(diffs, lineArray); 143 | return diffs; 144 | } 145 | 146 | /** 147 | * stacked prev, current data 148 | */ 149 | const diffsMap = diffLines(prev, current).reduce( 150 | (acc: Array, curr) => { 151 | const type = getDiffType(curr[0]); 152 | 153 | if (type === 'equal') { 154 | acc.push([curr]); // Push index 0 155 | } 156 | 157 | if (type === 'removed') { 158 | acc.push([curr]); // Push index 0 159 | } 160 | 161 | if (type === 'added') { 162 | const prev = 163 | acc.length && acc[acc.length - 1][0] ? acc[acc.length - 1][0] : null; 164 | if (prev && getDiffType(prev[0]) === 'removed') { 165 | acc[acc.length - 1].push(curr); // Push index 1 if index 0 has removed data in last array 166 | } else { 167 | acc.push([curr]); // Push index 0 168 | } 169 | } 170 | 171 | return acc; 172 | }, 173 | [], 174 | ); 175 | 176 | /** 177 | * Set index 1 in stacked data 178 | */ 179 | diffsMap.map(diffs => { 180 | if (diffs.length > 1) return; // Return if has index 0, 1 181 | 182 | const type = getDiffType(diffs[0][0]); 183 | 184 | if (type === 'added') { 185 | diffs.unshift([2, '']); // Set empty data 186 | } else if (type === 'removed') { 187 | diffs.push([2, '']); // Set empty data 188 | } else if (type === 'equal') { 189 | diffs.push([...diffs[0]]); // Set same data 190 | } 191 | }); 192 | 193 | /** 194 | * Get lines object on the mode 195 | */ 196 | if (mode === 'split') { 197 | return getSplitLines(diffsMap); 198 | } else if (mode === 'unified') { 199 | return getUnifiedLines(diffsMap); 200 | } else { 201 | return []; 202 | } 203 | }; 204 | 205 | /** 206 | * Render with modified tags 207 | * @param prev 208 | * @param current 209 | */ 210 | const renderWords = (prev: string, current: string) => { 211 | /** 212 | * Set modified tags in changed words (removed -> added) 213 | */ 214 | const dmp = new DiffMatchPatch(); 215 | const diff = dmp.diff_main(prev, current); 216 | dmp.diff_cleanupSemantic(diff); 217 | return diff 218 | .filter(result => getDiffType(result[0]) !== 'removed') 219 | .map(result => { 220 | return getDiffType(result[0]) === 'added' 221 | ? `${MODIFIED_START_TAG}${result[1]}${MODIFIED_CLOSE_TAG}` 222 | : result[1]; 223 | }) 224 | .join(''); 225 | }; 226 | 227 | /** 228 | * Set hightlight code 229 | * This function must calling at client only (use DOM) 230 | */ 231 | const setHighlightCode = ({ 232 | highlightCode, 233 | language, 234 | code, 235 | }: { 236 | highlightCode: Ref; 237 | language: string; 238 | code: string; 239 | }) => { 240 | const hasModifiedTags = code.match( 241 | new RegExp(`(${MODIFIED_START_TAG}|${MODIFIED_CLOSE_TAG})`, 'g'), 242 | ); 243 | 244 | if (!hasModifiedTags) { 245 | highlightCode.value = hljs.highlight(code, { language }).value; 246 | return; 247 | } 248 | 249 | /** 250 | * Explore highlight DOM extracted from pure code and compare the text with the original code code to generate the highlight code 251 | */ 252 | let originalCode = code; // original code with modified tags 253 | const pureCode = code.replace( 254 | new RegExp(`(${MODIFIED_START_TAG}|${MODIFIED_CLOSE_TAG})`, 'g'), 255 | '', 256 | ); // Without modified tags 257 | let pureElement = document.createElement('div'); 258 | pureElement.innerHTML = hljs.highlight(pureCode, { language }).value; // Highlight DOM without modified tags 259 | 260 | // Modified span is created per highlight operator and causes it to continue 261 | let innerModifiedTag = false; 262 | 263 | const diffElements = (node: HTMLElement) => { 264 | node.childNodes.forEach(child => { 265 | if (child.nodeType === 1) { 266 | diffElements(child as HTMLElement); 267 | } 268 | 269 | // Compare text nodes and check changed text 270 | if (child.nodeType === 3) { 271 | if (!child.textContent) return; 272 | 273 | let oldContent = child.textContent; 274 | let newContent = ''; 275 | 276 | if (innerModifiedTag) { 277 | // If it continues within the modified range 278 | newContent = newContent + MODIFIED_START_TAG; 279 | } 280 | 281 | while (oldContent.length) { 282 | if (originalCode.startsWith(MODIFIED_START_TAG)) { 283 | // Add modified start tag 284 | originalCode = originalCode.slice(MODIFIED_START_TAG.length); 285 | newContent = newContent + MODIFIED_START_TAG; 286 | innerModifiedTag = true; // Start modified 287 | continue; 288 | } 289 | if (originalCode.startsWith(MODIFIED_CLOSE_TAG)) { 290 | // Add modified close tag 291 | originalCode = originalCode.slice(MODIFIED_CLOSE_TAG.length); 292 | newContent = newContent + MODIFIED_CLOSE_TAG; 293 | innerModifiedTag = false; // End modified 294 | continue; 295 | } 296 | 297 | // Add words before modified tag 298 | const hasModifiedTag = originalCode.match( 299 | new RegExp(`(${MODIFIED_START_TAG}|${MODIFIED_CLOSE_TAG})`), 300 | ); 301 | const originalCodeDiffLength = 302 | hasModifiedTag && hasModifiedTag.index 303 | ? hasModifiedTag.index 304 | : originalCode.length; 305 | const nextDiffsLength = Math.min( 306 | originalCodeDiffLength, 307 | oldContent.length, 308 | ); 309 | 310 | newContent = newContent + originalCode.substring(0, nextDiffsLength); 311 | originalCode = originalCode.slice(nextDiffsLength); 312 | oldContent = oldContent.slice(nextDiffsLength); 313 | } 314 | 315 | if (innerModifiedTag) { 316 | // If the loop is finished without a modified close, it is still within the modified range. 317 | newContent = newContent + MODIFIED_CLOSE_TAG; 318 | } 319 | 320 | child.textContent = newContent; // put as entity code because change textContent 321 | } 322 | }); 323 | }; 324 | diffElements(pureElement); 325 | 326 | const startEntity = MODIFIED_START_TAG.replace('<', '<').replace( 327 | '>', 328 | '>', 329 | ); 330 | const closeEntity = MODIFIED_CLOSE_TAG.replace('<', '<').replace( 331 | '>', 332 | '>', 333 | ); 334 | 335 | highlightCode.value = pureElement.innerHTML 336 | .replace(new RegExp(startEntity, 'g'), '') 337 | .replace(new RegExp(closeEntity, 'g'), ''); 338 | 339 | // @ts-ignore 340 | pureElement = null; 341 | }; 342 | 343 | export { 344 | MODIFIED_START_TAG, 345 | MODIFIED_CLOSE_TAG, 346 | getDiffType, 347 | getSplitLines, 348 | getUnifiedLines, 349 | renderLines, 350 | renderWords, 351 | setHighlightCode, 352 | }; 353 | -------------------------------------------------------------------------------- /dist/index.umd.js: -------------------------------------------------------------------------------- 1 | var Ir=Object.defineProperty,Cr=Object.defineProperties;var Br=Object.getOwnPropertyDescriptors;var Nt=Object.getOwnPropertySymbols;var jr=Object.prototype.hasOwnProperty,Lr=Object.prototype.propertyIsEnumerable;var Ot=(H,h,q)=>h in H?Ir(H,h,{enumerable:!0,configurable:!0,writable:!0,value:q}):H[h]=q,we=(H,h)=>{for(var q in h||(h={}))jr.call(h,q)&&Ot(H,q,h[q]);if(Nt)for(var q of Nt(h))Lr.call(h,q)&&Ot(H,q,h[q]);return H},At=(H,h)=>Cr(H,Br(h));(function(H,h){typeof exports=="object"&&typeof module!="undefined"?h(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],h):(H=typeof globalThis!="undefined"?globalThis:H||self,h(H["vue-diff"]={},H.Vue))})(this,function(H,h){"use strict";function q(e){return h.getCurrentScope()?(h.onScopeDispose(e),!0):!1}const Le=typeof window!="undefined";function Pe(e,i){function l(...c){e(()=>i.apply(this,c),{fn:i,thisArg:this,args:c})}return l}const Mt=e=>e();function St(e,i={}){let l,c;return n=>{const t=h.unref(e),r=h.unref(i.maxWait);if(l&&clearTimeout(l),t<=0||r!==void 0&&r<=0)return c&&(clearTimeout(c),c=null),n();r&&!c&&(c=setTimeout(()=>{l&&clearTimeout(l),c=null,n()},r)),l=setTimeout(()=>{c&&clearTimeout(c),c=null,n()},t)}}function Rt(e,i=!0,l=!0){let c=0,u,n=!l;const t=()=>{u&&(clearTimeout(u),u=void 0)};return a=>{const o=h.unref(e),s=Date.now()-c;if(t(),o<=0)return c=Date.now(),a();s>o&&(c=Date.now(),n?n=!1:a()),i&&(u=setTimeout(()=>{c=Date.now(),l||(n=!0),t(),a()},o)),!l&&!u&&(u=setTimeout(()=>n=!0,o))}}function ce(e,i=200,l=!0,c=!0){return Pe(Rt(i,l,c),e)}var ze=Object.getOwnPropertySymbols,Tt=Object.prototype.hasOwnProperty,Dt=Object.prototype.propertyIsEnumerable,It=(e,i)=>{var l={};for(var c in e)Tt.call(e,c)&&i.indexOf(c)<0&&(l[c]=e[c]);if(e!=null&&ze)for(var c of ze(e))i.indexOf(c)<0&&Dt.call(e,c)&&(l[c]=e[c]);return l};function Ct(e,i,l={}){const c=l,{eventFilter:u=Mt}=c,n=It(c,["eventFilter"]);return h.watch(e,Pe(u,i),n)}var Bt=Object.defineProperty,jt=Object.defineProperties,Lt=Object.getOwnPropertyDescriptors,ge=Object.getOwnPropertySymbols,$e=Object.prototype.hasOwnProperty,Ue=Object.prototype.propertyIsEnumerable,He=(e,i,l)=>i in e?Bt(e,i,{enumerable:!0,configurable:!0,writable:!0,value:l}):e[i]=l,Pt=(e,i)=>{for(var l in i||(i={}))$e.call(i,l)&&He(e,l,i[l]);if(ge)for(var l of ge(i))Ue.call(i,l)&&He(e,l,i[l]);return e},zt=(e,i)=>jt(e,Lt(i)),$t=(e,i)=>{var l={};for(var c in e)$e.call(e,c)&&i.indexOf(c)<0&&(l[c]=e[c]);if(e!=null&&ge)for(var c of ge(e))i.indexOf(c)<0&&Ue.call(e,c)&&(l[c]=e[c]);return l};function Ze(e,i,l={}){const c=l,{debounce:u=0}=c,n=$t(c,["debounce"]);return Ct(e,i,zt(Pt({},n),{eventFilter:St(u)}))}function Ut(e){var i;const l=h.unref(e);return(i=l==null?void 0:l.$el)!=null?i:l}const Ht=Le?window:void 0,Ee=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{},xe="__vueuse_ssr_handlers__";Ee[xe]=Ee[xe]||{},Ee[xe];var Fe=Object.getOwnPropertySymbols,Zt=Object.prototype.hasOwnProperty,Ft=Object.prototype.propertyIsEnumerable,Gt=(e,i)=>{var l={};for(var c in e)Zt.call(e,c)&&i.indexOf(c)<0&&(l[c]=e[c]);if(e!=null&&Fe)for(var c of Fe(e))i.indexOf(c)<0&&Ft.call(e,c)&&(l[c]=e[c]);return l};function Kt(e,i,l={}){const c=l,{window:u=Ht}=c,n=Gt(c,["window"]);let t;const r=u&&"ResizeObserver"in u,a=()=>{t&&(t.disconnect(),t=void 0)},o=h.watch(()=>Ut(e),f=>{a(),r&&u&&f&&(t=new ResizeObserver(i),t.observe(f,n))},{immediate:!0,flush:"post"}),s=()=>{a(),o()};return q(s),{isSupported:r,stop:s}}var Ge,Ke;Le&&(window==null?void 0:window.navigator)&&((Ge=window==null?void 0:window.navigator)==null?void 0:Ge.platform)&&/iP(ad|hone|od)/.test((Ke=window==null?void 0:window.navigator)==null?void 0:Ke.platform);var ke={exports:{}};(function(e){var i=function(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32},l=-1,c=1,u=0;i.Diff=function(n,t){return[n,t]},i.prototype.diff_main=function(n,t,r,a){typeof a=="undefined"&&(this.Diff_Timeout<=0?a=Number.MAX_VALUE:a=new Date().getTime()+1e3*this.Diff_Timeout);var o=a;if(n==null||t==null)throw new Error("Null input. (diff_main)");if(n==t)return n?[new i.Diff(u,n)]:[];typeof r=="undefined"&&(r=!0);var s=r,f=this.diff_commonPrefix(n,t),d=n.substring(0,f);n=n.substring(f),t=t.substring(f),f=this.diff_commonSuffix(n,t);var g=n.substring(n.length-f);n=n.substring(0,n.length-f),t=t.substring(0,t.length-f);var p=this.diff_compute_(n,t,s,o);return d&&p.unshift(new i.Diff(u,d)),g&&p.push(new i.Diff(u,g)),this.diff_cleanupMerge(p),p},i.prototype.diff_compute_=function(n,t,r,a){var o;if(!n)return[new i.Diff(c,t)];if(!t)return[new i.Diff(l,n)];var s=n.length>t.length?n:t,f=n.length>t.length?t:n,d=s.indexOf(f);if(d!=-1)return o=[new i.Diff(c,s.substring(0,d)),new i.Diff(u,f),new i.Diff(c,s.substring(d+f.length))],n.length>t.length&&(o[0][0]=o[2][0]=l),o;if(f.length==1)return[new i.Diff(l,n),new i.Diff(c,t)];var g=this.diff_halfMatch_(n,t);if(g){var p=g[0],b=g[1],_=g[2],w=g[3],x=g[4],N=this.diff_main(p,_,r,a),A=this.diff_main(b,w,r,a);return N.concat([new i.Diff(u,x)],A)}return r&&n.length>100&&t.length>100?this.diff_lineMode_(n,t,a):this.diff_bisect_(n,t,a)},i.prototype.diff_lineMode_=function(n,t,r){var a=this.diff_linesToChars_(n,t);n=a.chars1,t=a.chars2;var o=a.lineArray,s=this.diff_main(n,t,!1,r);this.diff_charsToLines_(s,o),this.diff_cleanupSemantic(s),s.push(new i.Diff(u,""));for(var f=0,d=0,g=0,p="",b="";f=1&&g>=1){s.splice(f-d-g,d+g),f=f-d-g;for(var _=this.diff_main(p,b,!1,r),w=_.length-1;w>=0;w--)s.splice(f,0,_[w]);f+=_.length}g=0,d=0,p="",b="";break}f++}return s.pop(),s},i.prototype.diff_bisect_=function(n,t,r){for(var a=n.length,o=t.length,s=Math.ceil((a+o)/2),f=s,d=2*s,g=new Array(d),p=new Array(d),b=0;br);R++){for(var I=-R+x;I<=R-N;I+=2){var C=f+I,T;I==-R||I!=R&&g[C-1]a)N+=2;else if($>o)x+=2;else if(w){var P=f+_-I;if(P>=0&&P=L)return this.diff_bisectSplit_(n,t,T,$,r)}}}for(var U=-R+A;U<=R-D;U+=2){var P=f+U,L;U==-R||U!=R&&p[P-1]a)D+=2;else if(Z>o)A+=2;else if(!w){var C=f+_-U;if(C>=0&&C=L)return this.diff_bisectSplit_(n,t,T,$,r)}}}}return[new i.Diff(l,n),new i.Diff(c,t)]},i.prototype.diff_bisectSplit_=function(n,t,r,a,o){var s=n.substring(0,r),f=t.substring(0,a),d=n.substring(r),g=t.substring(a),p=this.diff_main(s,f,!1,o),b=this.diff_main(d,g,!1,o);return p.concat(b)},i.prototype.diff_linesToChars_=function(n,t){var r=[],a={};r[0]="";function o(g){for(var p="",b=0,_=-1,w=r.length;_a?n=n.substring(r-a):rt.length?n:t,a=n.length>t.length?t:n;if(r.length<4||2*a.length=N.length?[T,$,P,L,C]:null}var f=s(r,a,Math.ceil(r.length/4)),d=s(r,a,Math.ceil(r.length/2)),g;if(!f&&!d)return null;d?f?g=f[4].length>d[4].length?f:d:g=d:g=f;var p,b,_,w;n.length>t.length?(p=g[0],b=g[1],_=g[2],w=g[3]):(_=g[0],w=g[1],p=g[2],b=g[3]);var x=g[4];return[p,b,_,w,x]},i.prototype.diff_cleanupSemantic=function(n){for(var t=!1,r=[],a=0,o=null,s=0,f=0,d=0,g=0,p=0;s0?r[a-1]:-1,f=0,d=0,g=0,p=0,o=null,t=!0)),s++;for(t&&this.diff_cleanupMerge(n),this.diff_cleanupSemanticLossless(n),s=1;s=x?(w>=b.length/2||w>=_.length/2)&&(n.splice(s,0,new i.Diff(u,_.substring(0,w))),n[s-1][1]=b.substring(0,b.length-w),n[s+1][1]=_.substring(w),s++):(x>=b.length/2||x>=_.length/2)&&(n.splice(s,0,new i.Diff(u,b.substring(0,x))),n[s-1][0]=c,n[s-1][1]=_.substring(0,_.length-x),n[s+1][0]=l,n[s+1][1]=b.substring(x),s++),s++}s++}},i.prototype.diff_cleanupSemanticLossless=function(n){function t(x,N){if(!x||!N)return 6;var A=x.charAt(x.length-1),D=N.charAt(0),R=A.match(i.nonAlphaNumericRegex_),I=D.match(i.nonAlphaNumericRegex_),C=R&&A.match(i.whitespaceRegex_),T=I&&D.match(i.whitespaceRegex_),$=C&&A.match(i.linebreakRegex_),P=T&&D.match(i.linebreakRegex_),L=$&&x.match(i.blanklineEndRegex_),U=P&&N.match(i.blanklineStartRegex_);return L||U?5:$||P?4:R&&!C&&T?3:C||T?2:R||I?1:0}for(var r=1;r=_&&(_=w,g=a,p=o,b=s)}n[r-1][1]!=g&&(g?n[r-1][1]=g:(n.splice(r-1,1),r--),n[r][1]=p,b?n[r+1][1]=b:(n.splice(r+1,1),r--))}r++}},i.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/,i.whitespaceRegex_=/\s/,i.linebreakRegex_=/[\r\n]/,i.blanklineEndRegex_=/\n\r?\n$/,i.blanklineStartRegex_=/^\r?\n\r?\n/,i.prototype.diff_cleanupEfficiency=function(n){for(var t=!1,r=[],a=0,o=null,s=0,f=!1,d=!1,g=!1,p=!1;s0?r[a-1]:-1,g=p=!1),t=!0)),s++;t&&this.diff_cleanupMerge(n)},i.prototype.diff_cleanupMerge=function(n){n.push(new i.Diff(u,""));for(var t=0,r=0,a=0,o="",s="",f;t1?(r!==0&&a!==0&&(f=this.diff_commonPrefix(s,o),f!==0&&(t-r-a>0&&n[t-r-a-1][0]==u?n[t-r-a-1][1]+=s.substring(0,f):(n.splice(0,0,new i.Diff(u,s.substring(0,f))),t++),s=s.substring(f),o=o.substring(f)),f=this.diff_commonSuffix(s,o),f!==0&&(n[t][1]=s.substring(s.length-f)+n[t][1],s=s.substring(0,s.length-f),o=o.substring(0,o.length-f))),t-=r+a,n.splice(t,r+a),o.length&&(n.splice(t,0,new i.Diff(l,o)),t++),s.length&&(n.splice(t,0,new i.Diff(c,s)),t++),t++):t!==0&&n[t-1][0]==u?(n[t-1][1]+=n[t][1],n.splice(t,1)):t++,a=0,r=0,o="",s="";break}n[n.length-1][1]===""&&n.pop();var d=!1;for(t=1;tt));f++)o=r,s=a;return n.length!=f&&n[f][0]===l?s:s+(t-o)},i.prototype.diff_prettyHtml=function(n){for(var t=[],r=/&/g,a=//g,s=/\n/g,f=0;f");switch(d){case c:t[f]=''+p+"";break;case l:t[f]=''+p+"";break;case u:t[f]=""+p+"";break}}return t.join("")},i.prototype.diff_text1=function(n){for(var t=[],r=0;rthis.Match_MaxBits)throw new Error("Pattern too long for this browser.");var a=this.match_alphabet_(t),o=this;function s(T,$){var P=T/t.length,L=Math.abs(r-$);return o.Match_Distance?P+L/o.Match_Distance:L?1:P}var f=this.Match_Threshold,d=n.indexOf(t,r);d!=-1&&(f=Math.min(s(0,d),f),d=n.lastIndexOf(t,r+t.length),d!=-1&&(f=Math.min(s(0,d),f)));var g=1<=N;R--){var I=a[n.charAt(R-1)];if(x===0?D[R]=(D[R+1]<<1|1)&I:D[R]=(D[R+1]<<1|1)&I|((w[R+1]|w[R])<<1|1)|w[R+1],D[R]&g){var C=s(x,R-1);if(C<=f)if(f=C,d=R-1,d>r)N=Math.max(1,2*r-d);else break}}if(s(x+1,r)>f)break;w=D}return d},i.prototype.match_alphabet_=function(n){for(var t={},r=0;r2&&(this.diff_cleanupSemantic(o),this.diff_cleanupEfficiency(o));else if(n&&typeof n=="object"&&typeof t=="undefined"&&typeof r=="undefined")o=n,a=this.diff_text1(o);else if(typeof n=="string"&&t&&typeof t=="object"&&typeof r=="undefined")a=n,o=t;else if(typeof n=="string"&&typeof t=="string"&&r&&typeof r=="object")a=n,o=r;else throw new Error("Unknown call format to patch_make.");if(o.length===0)return[];for(var s=[],f=new i.patch_obj,d=0,g=0,p=0,b=a,_=a,w=0;w=2*this.Patch_Margin&&d&&(this.patch_addContext_(f,b),s.push(f),f=new i.patch_obj,d=0,b=_,g=p);break}x!==c&&(g+=N.length),x!==l&&(p+=N.length)}return d&&(this.patch_addContext_(f,b),s.push(f)),s},i.prototype.patch_deepCopy=function(n){for(var t=[],r=0;rthis.Match_MaxBits?(g=this.match_main(t,d.substring(0,this.Match_MaxBits),f),g!=-1&&(p=this.match_main(t,d.substring(d.length-this.Match_MaxBits),f+d.length-this.Match_MaxBits),(p==-1||g>=p)&&(g=-1))):g=this.match_main(t,d,f),g==-1)o[s]=!1,a-=n[s].length2-n[s].length1;else{o[s]=!0,a=g-f;var b;if(p==-1?b=t.substring(g,g+d.length):b=t.substring(g,p+this.Match_MaxBits),d==b)t=t.substring(0,g)+this.diff_text2(n[s].diffs)+t.substring(g+d.length);else{var _=this.diff_main(d,b,!1);if(d.length>this.Match_MaxBits&&this.diff_levenshtein(_)/d.length>this.Patch_DeleteThreshold)o[s]=!1;else{this.diff_cleanupSemanticLossless(_);for(var w=0,x,N=0;Ns[0][1].length){var f=t-s[0][1].length;s[0][1]=r.substring(s[0][1].length)+s[0][1],o.start1-=f,o.start2-=f,o.length1+=f,o.length2+=f}if(o=n[n.length-1],s=o.diffs,s.length==0||s[s.length-1][0]!=u)s.push(new i.Diff(u,r)),o.length1+=t,o.length2+=t;else if(t>s[s.length-1][1].length){var f=t-s[s.length-1][1].length;s[s.length-1][1]+=r.substring(0,f),o.length1+=f,o.length2+=f}return r},i.prototype.patch_splitMax=function(n){for(var t=this.Match_MaxBits,r=0;r2*t?(d.length1+=b.length,o+=b.length,g=!1,d.diffs.push(new i.Diff(p,b)),a.diffs.shift()):(b=b.substring(0,t-d.length1-this.Patch_Margin),d.length1+=b.length,o+=b.length,p===u?(d.length2+=b.length,s+=b.length):g=!1,d.diffs.push(new i.Diff(p,b)),b==a.diffs[0][1]?a.diffs.shift():a.diffs[0][1]=a.diffs[0][1].substring(b.length))}f=this.diff_text2(d.diffs),f=f.substring(f.length-this.Patch_Margin);var _=this.diff_text1(a.diffs).substring(0,this.Patch_Margin);_!==""&&(d.length1+=_.length,d.length2+=_.length,d.diffs.length!==0&&d.diffs[d.diffs.length-1][0]===u?d.diffs[d.diffs.length-1][1]+=_:d.diffs.push(new i.Diff(u,_))),g||n.splice(++r,0,d)}}},i.prototype.patch_toText=function(n){for(var t=[],r=0;r/g,">").replace(/"/g,""").replace(/'/g,"'")}function te(e,...i){const l=Object.create(null);for(const c in e)l[c]=e[c];return i.forEach(function(c){for(const u in c)l[u]=c[u]}),l}const Wt="",qe=e=>!!e.kind,qt=(e,{prefix:i})=>{if(e.includes(".")){const l=e.split(".");return[`${i}${l.shift()}`,...l.map((c,u)=>`${c}${"_".repeat(u+1)}`)].join(" ")}return`${i}${e}`};class Xt{constructor(i,l){this.buffer="",this.classPrefix=l.classPrefix,i.walk(this)}addText(i){this.buffer+=We(i)}openNode(i){if(!qe(i))return;let l=i.kind;i.sublanguage?l=`language-${l}`:l=qt(l,{prefix:this.classPrefix}),this.span(l)}closeNode(i){!qe(i)||(this.buffer+=Wt)}value(){return this.buffer}span(i){this.buffer+=``}}class Ae{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(i){this.top.children.push(i)}openNode(i){const l={kind:i,children:[]};this.add(l),this.stack.push(l)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(i){return this.constructor._walk(i,this.rootNode)}static _walk(i,l){return typeof l=="string"?i.addText(l):l.children&&(i.openNode(l),l.children.forEach(c=>this._walk(i,c)),i.closeNode(l)),i}static _collapse(i){typeof i!="string"&&(!i.children||(i.children.every(l=>typeof l=="string")?i.children=[i.children.join("")]:i.children.forEach(l=>{Ae._collapse(l)})))}}class Jt extends Ae{constructor(i){super(),this.options=i}addKeyword(i,l){i!==""&&(this.openNode(l),this.addText(i),this.closeNode())}addText(i){i!==""&&this.add(i)}addSublanguage(i,l){const c=i.root;c.kind=l,c.sublanguage=!0,this.add(c)}toHTML(){return new Xt(this,this.options).value()}finalize(){return!0}}function fe(e){return e?typeof e=="string"?e:e.source:null}function Xe(e){return ie("(?=",e,")")}function Qt(e){return ie("(?:",e,")*")}function Yt(e){return ie("(?:",e,")?")}function ie(...e){return e.map(l=>fe(l)).join("")}function en(e){const i=e[e.length-1];return typeof i=="object"&&i.constructor===Object?(e.splice(e.length-1,1),i):{}}function Me(...e){const i=en(e);return"("+(i.capture?"":"?:")+e.map(c=>fe(c)).join("|")+")"}function Je(e){return new RegExp(e.toString()+"|").exec("").length-1}function tn(e,i){const l=e&&e.exec(i);return l&&l.index===0}const nn=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function Se(e,{joinWith:i}){let l=0;return e.map(c=>{l+=1;const u=l;let n=fe(c),t="";for(;n.length>0;){const r=nn.exec(n);if(!r){t+=n;break}t+=n.substring(0,r.index),n=n.substring(r.index+r[0].length),r[0][0]==="\\"&&r[1]?t+="\\"+String(Number(r[1])+u):(t+=r[0],r[0]==="("&&l++)}return t}).map(c=>`(${c})`).join(i)}const rn=/\b\B/,Qe="[a-zA-Z]\\w*",Re="[a-zA-Z_]\\w*",Ye="\\b\\d+(\\.\\d+)?",et="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",tt="\\b(0b[01]+)",an="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",sn=(e={})=>{const i=/^#![ ]*\//;return e.binary&&(e.begin=ie(i,/.*\b/,e.binary,/\b.*/)),te({scope:"meta",begin:i,end:/$/,relevance:0,"on:begin":(l,c)=>{l.index!==0&&c.ignoreMatch()}},e)},de={begin:"\\\\[\\s\\S]",relevance:0},on={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[de]},ln={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[de]},cn={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},he=function(e,i,l={}){const c=te({scope:"comment",begin:e,end:i,contains:[]},l);c.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});const u=Me("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return c.contains.push({begin:ie(/[ ]+/,"(",u,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),c},fn=he("//","$"),dn=he("/\\*","\\*/"),un=he("#","$"),gn={scope:"number",begin:Ye,relevance:0},hn={scope:"number",begin:et,relevance:0},pn={scope:"number",begin:tt,relevance:0},bn={begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[de,{begin:/\[/,end:/\]/,relevance:0,contains:[de]}]}]},mn={scope:"title",begin:Qe,relevance:0},vn={scope:"title",begin:Re,relevance:0},_n={begin:"\\.\\s*"+Re,relevance:0};var pe=Object.freeze({__proto__:null,MATCH_NOTHING_RE:rn,IDENT_RE:Qe,UNDERSCORE_IDENT_RE:Re,NUMBER_RE:Ye,C_NUMBER_RE:et,BINARY_NUMBER_RE:tt,RE_STARTERS_RE:an,SHEBANG:sn,BACKSLASH_ESCAPE:de,APOS_STRING_MODE:on,QUOTE_STRING_MODE:ln,PHRASAL_WORDS_MODE:cn,COMMENT:he,C_LINE_COMMENT_MODE:fn,C_BLOCK_COMMENT_MODE:dn,HASH_COMMENT_MODE:un,NUMBER_MODE:gn,C_NUMBER_MODE:hn,BINARY_NUMBER_MODE:pn,REGEXP_MODE:bn,TITLE_MODE:mn,UNDERSCORE_TITLE_MODE:vn,METHOD_GUARD:_n,END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(i,l)=>{l.data._beginMatch=i[1]},"on:end":(i,l)=>{l.data._beginMatch!==i[1]&&l.ignoreMatch()}})}});function yn(e,i){e.input[e.index-1]==="."&&i.ignoreMatch()}function wn(e,i){e.className!==void 0&&(e.scope=e.className,delete e.className)}function En(e,i){!i||!e.beginKeywords||(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=yn,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,e.relevance===void 0&&(e.relevance=0))}function xn(e,i){!Array.isArray(e.illegal)||(e.illegal=Me(...e.illegal))}function kn(e,i){if(!!e.match){if(e.begin||e.end)throw new Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function Nn(e,i){e.relevance===void 0&&(e.relevance=1)}const On=(e,i)=>{if(!e.beforeMatch)return;if(e.starts)throw new Error("beforeMatch cannot be used with starts");const l=Object.assign({},e);Object.keys(e).forEach(c=>{delete e[c]}),e.keywords=l.keywords,e.begin=ie(l.beforeMatch,Xe(l.begin)),e.starts={relevance:0,contains:[Object.assign(l,{endsParent:!0})]},e.relevance=0,delete l.beforeMatch},An=["of","and","for","in","not","or","if","then","parent","list","value"],Mn="keyword";function nt(e,i,l=Mn){const c=Object.create(null);return typeof e=="string"?u(l,e.split(" ")):Array.isArray(e)?u(l,e):Object.keys(e).forEach(function(n){Object.assign(c,nt(e[n],i,n))}),c;function u(n,t){i&&(t=t.map(r=>r.toLowerCase())),t.forEach(function(r){const a=r.split("|");c[a[0]]=[n,Sn(a[0],a[1])]})}}function Sn(e,i){return i?Number(i):Rn(e)?0:1}function Rn(e){return An.includes(e.toLowerCase())}const rt={},ae=e=>{},it=(e,...i)=>{},le=(e,i)=>{rt[`${e}/${i}`]||(rt[`${e}/${i}`]=!0)},be=new Error;function at(e,i,{key:l}){let c=0;const u=e[l],n={},t={};for(let r=1;r<=i.length;r++)t[r+c]=u[r],n[r+c]=!0,c+=Je(i[r-1]);e[l]=t,e[l]._emit=n,e[l]._multi=!0}function Tn(e){if(!!Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw ae("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),be;if(typeof e.beginScope!="object"||e.beginScope===null)throw ae("beginScope must be object"),be;at(e,e.begin,{key:"beginScope"}),e.begin=Se(e.begin,{joinWith:""})}}function Dn(e){if(!!Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw ae("skip, excludeEnd, returnEnd not compatible with endScope: {}"),be;if(typeof e.endScope!="object"||e.endScope===null)throw ae("endScope must be object"),be;at(e,e.end,{key:"endScope"}),e.end=Se(e.end,{joinWith:""})}}function In(e){e.scope&&typeof e.scope=="object"&&e.scope!==null&&(e.beginScope=e.scope,delete e.scope)}function Cn(e){In(e),typeof e.beginScope=="string"&&(e.beginScope={_wrap:e.beginScope}),typeof e.endScope=="string"&&(e.endScope={_wrap:e.endScope}),Tn(e),Dn(e)}function Bn(e){function i(t,r){return new RegExp(fe(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(r?"g":""))}class l{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(r,a){a.position=this.position++,this.matchIndexes[this.matchAt]=a,this.regexes.push([a,r]),this.matchAt+=Je(r)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);const r=this.regexes.map(a=>a[1]);this.matcherRe=i(Se(r,{joinWith:"|"}),!0),this.lastIndex=0}exec(r){this.matcherRe.lastIndex=this.lastIndex;const a=this.matcherRe.exec(r);if(!a)return null;const o=a.findIndex((f,d)=>d>0&&f!==void 0),s=this.matchIndexes[o];return a.splice(0,o),Object.assign(a,s)}}class c{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(r){if(this.multiRegexes[r])return this.multiRegexes[r];const a=new l;return this.rules.slice(r).forEach(([o,s])=>a.addRule(o,s)),a.compile(),this.multiRegexes[r]=a,a}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(r,a){this.rules.push([r,a]),a.type==="begin"&&this.count++}exec(r){const a=this.getMatcher(this.regexIndex);a.lastIndex=this.lastIndex;let o=a.exec(r);if(this.resumingScanAtSamePosition()&&!(o&&o.index===this.lastIndex)){const s=this.getMatcher(0);s.lastIndex=this.lastIndex+1,o=s.exec(r)}return o&&(this.regexIndex+=o.position+1,this.regexIndex===this.count&&this.considerAll()),o}}function u(t){const r=new c;return t.contains.forEach(a=>r.addRule(a.begin,{rule:a,type:"begin"})),t.terminatorEnd&&r.addRule(t.terminatorEnd,{type:"end"}),t.illegal&&r.addRule(t.illegal,{type:"illegal"}),r}function n(t,r){const a=t;if(t.isCompiled)return a;[wn,kn,Cn,On].forEach(s=>s(t,r)),e.compilerExtensions.forEach(s=>s(t,r)),t.__beforeBegin=null,[En,xn,Nn].forEach(s=>s(t,r)),t.isCompiled=!0;let o=null;return typeof t.keywords=="object"&&t.keywords.$pattern&&(t.keywords=Object.assign({},t.keywords),o=t.keywords.$pattern,delete t.keywords.$pattern),o=o||/\w+/,t.keywords&&(t.keywords=nt(t.keywords,e.case_insensitive)),a.keywordPatternRe=i(o,!0),r&&(t.begin||(t.begin=/\B|\b/),a.beginRe=i(a.begin),!t.end&&!t.endsWithParent&&(t.end=/\B|\b/),t.end&&(a.endRe=i(a.end)),a.terminatorEnd=fe(a.end)||"",t.endsWithParent&&r.terminatorEnd&&(a.terminatorEnd+=(t.end?"|":"")+r.terminatorEnd)),t.illegal&&(a.illegalRe=i(t.illegal)),t.contains||(t.contains=[]),t.contains=[].concat(...t.contains.map(function(s){return jn(s==="self"?t:s)})),t.contains.forEach(function(s){n(s,a)}),t.starts&&n(t.starts,r),a.matcher=u(a),a}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=te(e.classNameAliases||{}),n(e)}function st(e){return e?e.endsWithParent||st(e.starts):!1}function jn(e){return e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(function(i){return te(e,{variants:null},i)})),e.cachedVariants?e.cachedVariants:st(e)?te(e,{starts:e.starts?te(e.starts):null}):Object.isFrozen(e)?te(e):e}var Ln="11.5.1";class Pn extends Error{constructor(i,l){super(i),this.name="HTMLInjectionError",this.html=l}}const Te=We,ot=te,lt=Symbol("nomatch"),zn=7;var ue=function(e){const i=Object.create(null),l=Object.create(null),c=[];let u=!0;const n="Could not find the language '{}', did you forget to load/include a language module?",t={disableAutodetect:!0,name:"Plain text",contains:[]};let r={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:Jt};function a(m){return r.noHighlightRe.test(m)}function o(m){let v=m.className+" ";v+=m.parentNode?m.parentNode.className:"";const k=r.languageDetectRe.exec(v);if(k){const S=T(k[1]);return S||(it(n.replace("{}",k[1])),it("Falling back to no-highlight mode for this block.",m)),S?k[1]:"no-highlight"}return v.split(/\s+/).find(S=>a(S)||T(S))}function s(m,v,k){let S="",B="";typeof v=="object"?(S=m,k=v.ignoreIllegals,B=v.language):(le("10.7.0","highlight(lang, code, ...args) has been deprecated."),le("10.7.0",`Please use highlight(code, options) instead. 6 | https://github.com/highlightjs/highlight.js/issues/2277`),B=m,S=v),k===void 0&&(k=!0);const G={code:S,language:B};Z("before:highlight",G);const J=G.result?G.result:f(G.language,G.code,k);return J.code=G.code,Z("after:highlight",J),J}function f(m,v,k,S){const B=Object.create(null);function G(y,E){return y.keywords[E]}function J(){if(!O.keywords){F.addText(z);return}let y=0;O.keywordPatternRe.lastIndex=0;let E=O.keywordPatternRe.exec(z),M="";for(;E;){M+=z.substring(y,E.index);const j=re.case_insensitive?E[0].toLowerCase():E[0],K=G(O,j);if(K){const[ee,Tr]=K;if(F.addText(M),M="",B[j]=(B[j]||0)+1,B[j]<=zn&&(ye+=Tr),ee.startsWith("_"))M+=E[0];else{const Dr=re.classNameAliases[ee]||ee;F.addKeyword(E[0],Dr)}}else M+=E[0];y=O.keywordPatternRe.lastIndex,E=O.keywordPatternRe.exec(z)}M+=z.substr(y),F.addText(M)}function ve(){if(z==="")return;let y=null;if(typeof O.subLanguage=="string"){if(!i[O.subLanguage]){F.addText(z);return}y=f(O.subLanguage,z,!0,kt[O.subLanguage]),kt[O.subLanguage]=y._top}else y=g(z,O.subLanguage.length?O.subLanguage:null);O.relevance>0&&(ye+=y.relevance),F.addSublanguage(y._emitter,y.language)}function W(){O.subLanguage!=null?ve():J(),z=""}function ne(y,E){let M=1;const j=E.length-1;for(;M<=j;){if(!y._emit[M]){M++;continue}const K=re.classNameAliases[y[M]]||y[M],ee=E[M];K?F.addKeyword(ee,K):(z=ee,J(),z=""),M++}}function wt(y,E){return y.scope&&typeof y.scope=="string"&&F.openNode(re.classNameAliases[y.scope]||y.scope),y.beginScope&&(y.beginScope._wrap?(F.addKeyword(z,re.classNameAliases[y.beginScope._wrap]||y.beginScope._wrap),z=""):y.beginScope._multi&&(ne(y.beginScope,E),z="")),O=Object.create(y,{parent:{value:O}}),O}function Et(y,E,M){let j=tn(y.endRe,M);if(j){if(y["on:end"]){const K=new Ve(y);y["on:end"](E,K),K.isMatchIgnored&&(j=!1)}if(j){for(;y.endsParent&&y.parent;)y=y.parent;return y}}if(y.endsWithParent)return Et(y.parent,E,M)}function Or(y){return O.matcher.regexIndex===0?(z+=y[0],1):(je=!0,0)}function Ar(y){const E=y[0],M=y.rule,j=new Ve(M),K=[M.__beforeBegin,M["on:begin"]];for(const ee of K)if(!!ee&&(ee(y,j),j.isMatchIgnored))return Or(E);return M.skip?z+=E:(M.excludeBegin&&(z+=E),W(),!M.returnBegin&&!M.excludeBegin&&(z=E)),wt(M,y),M.returnBegin?0:E.length}function Mr(y){const E=y[0],M=v.substr(y.index),j=Et(O,y,M);if(!j)return lt;const K=O;O.endScope&&O.endScope._wrap?(W(),F.addKeyword(E,O.endScope._wrap)):O.endScope&&O.endScope._multi?(W(),ne(O.endScope,y)):K.skip?z+=E:(K.returnEnd||K.excludeEnd||(z+=E),W(),K.excludeEnd&&(z=E));do O.scope&&F.closeNode(),!O.skip&&!O.subLanguage&&(ye+=O.relevance),O=O.parent;while(O!==j.parent);return j.starts&&wt(j.starts,y),K.returnEnd?0:E.length}function Sr(){const y=[];for(let E=O;E!==re;E=E.parent)E.scope&&y.unshift(E.scope);y.forEach(E=>F.openNode(E))}let _e={};function xt(y,E){const M=E&&E[0];if(z+=y,M==null)return W(),0;if(_e.type==="begin"&&E.type==="end"&&_e.index===E.index&&M===""){if(z+=v.slice(E.index,E.index+1),!u){const j=new Error(`0 width match regex (${m})`);throw j.languageName=m,j.badRule=_e.rule,j}return 1}if(_e=E,E.type==="begin")return Ar(E);if(E.type==="illegal"&&!k){const j=new Error('Illegal lexeme "'+M+'" for mode "'+(O.scope||"")+'"');throw j.mode=O,j}else if(E.type==="end"){const j=Mr(E);if(j!==lt)return j}if(E.type==="illegal"&&M==="")return 1;if(Be>1e5&&Be>3*E.index)throw new Error("potential infinite loop, way more iterations than matches");return z+=M,M.length}const re=T(m);if(!re)throw ae(n.replace("{}",m)),new Error('Unknown language: "'+m+'"');const Rr=Bn(re);let Ce="",O=S||Rr;const kt={},F=new r.__emitter(r);Sr();let z="",ye=0,oe=0,Be=0,je=!1;try{for(O.matcher.considerAll();;){Be++,je?je=!1:O.matcher.considerAll(),O.matcher.lastIndex=oe;const y=O.matcher.exec(v);if(!y)break;const E=v.substring(oe,y.index),M=xt(E,y);oe=y.index+M}return xt(v.substr(oe)),F.closeAllNodes(),F.finalize(),Ce=F.toHTML(),{language:m,value:Ce,relevance:ye,illegal:!1,_emitter:F,_top:O}}catch(y){if(y.message&&y.message.includes("Illegal"))return{language:m,value:Te(v),illegal:!0,relevance:0,_illegalBy:{message:y.message,index:oe,context:v.slice(oe-100,oe+100),mode:y.mode,resultSoFar:Ce},_emitter:F};if(u)return{language:m,value:Te(v),illegal:!1,relevance:0,errorRaised:y,_emitter:F,_top:O};throw y}}function d(m){const v={value:Te(m),illegal:!1,relevance:0,_top:t,_emitter:new r.__emitter(r)};return v._emitter.addText(m),v}function g(m,v){v=v||r.languages||Object.keys(i);const k=d(m),S=v.filter(T).filter(P).map(W=>f(W,m,!1));S.unshift(k);const B=S.sort((W,ne)=>{if(W.relevance!==ne.relevance)return ne.relevance-W.relevance;if(W.language&&ne.language){if(T(W.language).supersetOf===ne.language)return 1;if(T(ne.language).supersetOf===W.language)return-1}return 0}),[G,J]=B,ve=G;return ve.secondBest=J,ve}function p(m,v,k){const S=v&&l[v]||k;m.classList.add("hljs"),m.classList.add(`language-${S}`)}function b(m){let v=null;const k=o(m);if(a(k))return;if(Z("before:highlightElement",{el:m,language:k}),m.children.length>0&&(r.ignoreUnescapedHTML,r.throwUnescapedHTML))throw new Pn("One of your code blocks includes unescaped HTML.",m.innerHTML);v=m;const S=v.textContent,B=k?s(S,{language:k,ignoreIllegals:!0}):g(S);m.innerHTML=B.value,p(m,k,B.language),m.result={language:B.language,re:B.relevance,relevance:B.relevance},B.secondBest&&(m.secondBest={language:B.secondBest.language,relevance:B.secondBest.relevance}),Z("after:highlightElement",{el:m,result:B,text:S})}function _(m){r=ot(r,m)}const w=()=>{A(),le("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function x(){A(),le("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let N=!1;function A(){if(document.readyState==="loading"){N=!0;return}document.querySelectorAll(r.cssSelector).forEach(b)}function D(){N&&A()}typeof window!="undefined"&&window.addEventListener&&window.addEventListener("DOMContentLoaded",D,!1);function R(m,v){let k=null;try{k=v(e)}catch(S){if(ae("Language definition for '{}' could not be registered.".replace("{}",m)),u)ae(S);else throw S;k=t}k.name||(k.name=m),i[m]=k,k.rawDefinition=v.bind(null,e),k.aliases&&$(k.aliases,{languageName:m})}function I(m){delete i[m];for(const v of Object.keys(l))l[v]===m&&delete l[v]}function C(){return Object.keys(i)}function T(m){return m=(m||"").toLowerCase(),i[m]||i[l[m]]}function $(m,{languageName:v}){typeof m=="string"&&(m=[m]),m.forEach(k=>{l[k.toLowerCase()]=v})}function P(m){const v=T(m);return v&&!v.disableAutodetect}function L(m){m["before:highlightBlock"]&&!m["before:highlightElement"]&&(m["before:highlightElement"]=v=>{m["before:highlightBlock"](Object.assign({block:v.el},v))}),m["after:highlightBlock"]&&!m["after:highlightElement"]&&(m["after:highlightElement"]=v=>{m["after:highlightBlock"](Object.assign({block:v.el},v))})}function U(m){L(m),c.push(m)}function Z(m,v){const k=m;c.forEach(function(S){S[k]&&S[k](v)})}function se(m){return le("10.7.0","highlightBlock will be removed entirely in v12.0"),le("10.7.0","Please use highlightElement now."),b(m)}Object.assign(e,{highlight:s,highlightAuto:g,highlightAll:A,highlightElement:b,highlightBlock:se,configure:_,initHighlighting:w,initHighlightingOnLoad:x,registerLanguage:R,unregisterLanguage:I,listLanguages:C,getLanguage:T,registerAliases:$,autoDetection:P,inherit:ot,addPlugin:U}),e.debugMode=function(){u=!1},e.safeMode=function(){u=!0},e.versionString=Ln,e.regex={concat:ie,lookahead:Xe,either:Me,optional:Yt,anyNumberOfTimes:Qt};for(const m in pe)typeof pe[m]=="object"&&Vt(pe[m]);return Object.assign(e,pe),e}({}),$n=ue;ue.HighlightJS=ue,ue.default=ue;var X=$n;const Un=e=>({IMPORTANT:{scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{scope:"number",begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z][A-Za-z0-9_-]*/}}),Hn=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],Zn=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],Fn=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],Gn=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],Kn=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse();function Vn(e){const i=e.regex,l=Un(e),c={begin:/-(webkit|moz|ms|o)-(?=[a-z])/},u="and or not only",n=/@-?\w[\w]*(-\w+)*/,t="[a-zA-Z-][a-zA-Z0-9_-]*",r=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"},contains:[l.BLOCK_COMMENT,c,l.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{className:"selector-class",begin:"\\."+t,relevance:0},l.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{begin:":("+Fn.join("|")+")"},{begin:":(:)?("+Gn.join("|")+")"}]},l.CSS_VARIABLE,{className:"attribute",begin:"\\b("+Kn.join("|")+")\\b"},{begin:/:/,end:/[;}{]/,contains:[l.BLOCK_COMMENT,l.HEXCOLOR,l.IMPORTANT,l.CSS_NUMBER_MODE,...r,{begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"},contains:[{className:"string",begin:/[^)]/,endsWithParent:!0,excludeEnd:!0}]},l.FUNCTION_DISPATCH]},{begin:i.lookahead(/@/),end:"[{;]",relevance:0,illegal:/:/,contains:[{className:"keyword",begin:n},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{$pattern:/[a-z-]+/,keyword:u,attribute:Zn.join(" ")},contains:[{begin:/[a-z-]+(?=:)/,className:"attribute"},...r,l.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"\\b("+Hn.join("|")+")\\b"}]}}function Wn(e){const i=e.regex,l=i.concat(/[A-Z_]/,i.optional(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),c=/[A-Za-z0-9._:-]+/,u={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},n={begin:/\s/,contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},t=e.inherit(n,{begin:/\(/,end:/\)/}),r=e.inherit(e.APOS_STRING_MODE,{className:"string"}),a=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),o={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[n,a,r,t,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[n,t,a,r]}]}]},e.COMMENT(//,{relevance:10}),{begin://,relevance:10},u,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/,relevance:10,contains:[a]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[o],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[o],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:i.concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:l,relevance:0,starts:o}]},{className:"tag",begin:i.concat(/<\//,i.lookahead(i.concat(l,/>/))),contains:[{className:"name",begin:l,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}function qn(e){const i=e.regex,l={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},c={begin:"^[-\\*]{3,}",end:"$"},u={className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},n={className:"bullet",begin:"^[ ]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},t={begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},r=/[A-Za-z][A-Za-z0-9+.-]*/,a={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/,relevance:2},{begin:i.concat(/\[.+?\]\(/,r,/:\/\/.*?\)/),relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}]},o={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]},f=e.inherit(o,{contains:[]}),d=e.inherit(s,{contains:[]});o.contains.push(d),s.contains.push(f);let g=[l,a];return[o,s,f,d].forEach(_=>{_.contains=_.contains.concat(g)}),g=g.concat(o,s),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:g},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:g}]}]},l,n,o,s,{className:"quote",begin:"^>\\s+",contains:g,end:"$"},u,c,a,t]}}const ct="[A-Za-z$_][0-9A-Za-z$_]*",Xn=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],Jn=["true","false","null","undefined","NaN","Infinity"],ft=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],dt=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],ut=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],Qn=["arguments","this","super","console","window","document","localStorage","module","global"],Yn=[].concat(ut,ft,dt);function er(e){const i=e.regex,l=(v,{after:k})=>{const S="",end:""},n=/<[A-Za-z0-9\\._:-]+\s*\/>/,t={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(v,k)=>{const S=v[0].length+v.index,B=v.input[S];if(B==="<"||B===","){k.ignoreMatch();return}B===">"&&(l(v,{after:S})||k.ignoreMatch());let G;if((G=v.input.substr(S).match(/^\s+extends\s+/))&&G.index===0){k.ignoreMatch();return}}},r={$pattern:ct,keyword:Xn,literal:Jn,built_in:Yn,"variable.language":Qn},a="[0-9](_?[0-9])*",o=`\\.(${a})`,s="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",f={className:"number",variants:[{begin:`(\\b(${s})((${o})|\\.)?|(${o}))[eE][+-]?(${a})\\b`},{begin:`\\b(${s})\\b((${o})\\b|\\.)?|(${o})\\b`},{begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{begin:"\\b0[0-7]+n?\\b"}],relevance:0},d={className:"subst",begin:"\\$\\{",end:"\\}",keywords:r,contains:[]},g={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,d],subLanguage:"xml"}},p={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,d],subLanguage:"css"}},b={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,d]},_=e.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,excludeBegin:!0,relevance:0},{className:"variable",begin:c+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),w={className:"comment",variants:[_,e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]},x=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,g,p,b,f];d.contains=x.concat({begin:/\{/,end:/\}/,keywords:r,contains:["self"].concat(x)});const N=[].concat(w,d.contains),A=N.concat([{begin:/\(/,end:/\)/,keywords:r,contains:["self"].concat(N)}]),D={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:r,contains:A},R={variants:[{match:[/class/,/\s+/,c,/\s+/,/extends/,/\s+/,i.concat(c,"(",i.concat(/\./,c),")*")],scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{match:[/class/,/\s+/,c],scope:{1:"keyword",3:"title.class"}}]},I={relevance:0,match:i.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/),className:"title.class",keywords:{_:[...ft,...dt]}},C={label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},T={variants:[{match:[/function/,/\s+/,c,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}],className:{1:"keyword",3:"title.function"},label:"func.def",contains:[D],illegal:/%/},$={relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"};function P(v){return i.concat("(?!",v.join("|"),")")}const L={match:i.concat(/\b/,P([...ut,"super"]),c,i.lookahead(/\(/)),className:"title.function",relevance:0},U={begin:i.concat(/\./,i.lookahead(i.concat(c,/(?![0-9A-Za-z$_(])/))),end:c,excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},Z={match:[/get|set/,/\s+/,c,/(?=\()/],className:{1:"keyword",3:"title.function"},contains:[{begin:/\(\)/},D]},se="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",m={match:[/const|var|let/,/\s+/,c,/\s*/,/=\s*/,/(async\s*)?/,i.lookahead(se)],keywords:"async",className:{1:"keyword",3:"title.function"},contains:[D]};return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:r,exports:{PARAMS_CONTAINS:A,CLASS_REFERENCE:I},illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),C,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,g,p,b,w,f,I,{className:"attr",begin:c+i.lookahead(":"),relevance:0},m,{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",relevance:0,contains:[w,e.REGEXP_MODE,{className:"function",begin:se,returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:r,contains:A}]}]},{begin:/,/,relevance:0},{match:/\s+/,relevance:0},{variants:[{begin:u.begin,end:u.end},{match:n},{begin:t.begin,"on:begin":t.isTrulyOpeningTag,end:t.end}],subLanguage:"xml",contains:[{begin:t.begin,end:t.end,skip:!0,contains:["self"]}]}]},T,{beginKeywords:"while if switch catch for"},{begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,label:"func.def",contains:[D,e.inherit(e.TITLE_MODE,{begin:c,className:"title.function"})]},{match:/\.\.\./,relevance:0},U,{match:"\\$"+c,relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},contains:[D]},L,$,R,Z,{match:/\$[(.]/}]}}function tr(e){const i={className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},l={match:/[{}[\],:]/,className:"punctuation",relevance:0},c={beginKeywords:["true","false","null"].join(" ")};return{name:"JSON",contains:[i,l,e.QUOTE_STRING_MODE,c,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE],illegal:"\\S"}}function nr(e){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}const me="[A-Za-z$_][0-9A-Za-z$_]*",gt=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],ht=["true","false","null","undefined","NaN","Infinity"],pt=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],bt=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],mt=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],vt=["arguments","this","super","console","window","document","localStorage","module","global"],_t=[].concat(mt,pt,bt);function rr(e){const i=e.regex,l=(v,{after:k})=>{const S="",end:""},n=/<[A-Za-z0-9\\._:-]+\s*\/>/,t={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(v,k)=>{const S=v[0].length+v.index,B=v.input[S];if(B==="<"||B===","){k.ignoreMatch();return}B===">"&&(l(v,{after:S})||k.ignoreMatch());let G;if((G=v.input.substr(S).match(/^\s+extends\s+/))&&G.index===0){k.ignoreMatch();return}}},r={$pattern:me,keyword:gt,literal:ht,built_in:_t,"variable.language":vt},a="[0-9](_?[0-9])*",o=`\\.(${a})`,s="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",f={className:"number",variants:[{begin:`(\\b(${s})((${o})|\\.)?|(${o}))[eE][+-]?(${a})\\b`},{begin:`\\b(${s})\\b((${o})\\b|\\.)?|(${o})\\b`},{begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{begin:"\\b0[0-7]+n?\\b"}],relevance:0},d={className:"subst",begin:"\\$\\{",end:"\\}",keywords:r,contains:[]},g={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,d],subLanguage:"xml"}},p={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[e.BACKSLASH_ESCAPE,d],subLanguage:"css"}},b={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,d]},_=e.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0,excludeBegin:!0,relevance:0},{className:"variable",begin:c+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),w={className:"comment",variants:[_,e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]},x=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,g,p,b,f];d.contains=x.concat({begin:/\{/,end:/\}/,keywords:r,contains:["self"].concat(x)});const N=[].concat(w,d.contains),A=N.concat([{begin:/\(/,end:/\)/,keywords:r,contains:["self"].concat(N)}]),D={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:r,contains:A},R={variants:[{match:[/class/,/\s+/,c,/\s+/,/extends/,/\s+/,i.concat(c,"(",i.concat(/\./,c),")*")],scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{match:[/class/,/\s+/,c],scope:{1:"keyword",3:"title.class"}}]},I={relevance:0,match:i.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/),className:"title.class",keywords:{_:[...pt,...bt]}},C={label:"use_strict",className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},T={variants:[{match:[/function/,/\s+/,c,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}],className:{1:"keyword",3:"title.function"},label:"func.def",contains:[D],illegal:/%/},$={relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"};function P(v){return i.concat("(?!",v.join("|"),")")}const L={match:i.concat(/\b/,P([...mt,"super"]),c,i.lookahead(/\(/)),className:"title.function",relevance:0},U={begin:i.concat(/\./,i.lookahead(i.concat(c,/(?![0-9A-Za-z$_(])/))),end:c,excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},Z={match:[/get|set/,/\s+/,c,/(?=\()/],className:{1:"keyword",3:"title.function"},contains:[{begin:/\(\)/},D]},se="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+e.UNDERSCORE_IDENT_RE+")\\s*=>",m={match:[/const|var|let/,/\s+/,c,/\s*/,/=\s*/,/(async\s*)?/,i.lookahead(se)],keywords:"async",className:{1:"keyword",3:"title.function"},contains:[D]};return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:r,exports:{PARAMS_CONTAINS:A,CLASS_REFERENCE:I},illegal:/#(?![$_A-z])/,contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),C,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,g,p,b,w,f,I,{className:"attr",begin:c+i.lookahead(":"),relevance:0},m,{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",relevance:0,contains:[w,e.REGEXP_MODE,{className:"function",begin:se,returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:r,contains:A}]}]},{begin:/,/,relevance:0},{match:/\s+/,relevance:0},{variants:[{begin:u.begin,end:u.end},{match:n},{begin:t.begin,"on:begin":t.isTrulyOpeningTag,end:t.end}],subLanguage:"xml",contains:[{begin:t.begin,end:t.end,skip:!0,contains:["self"]}]}]},T,{beginKeywords:"while if switch catch for"},{begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,label:"func.def",contains:[D,e.inherit(e.TITLE_MODE,{begin:c,className:"title.function"})]},{match:/\.\.\./,relevance:0},U,{match:"\\$"+c,relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"},contains:[D]},L,$,R,Z,{match:/\$[(.]/}]}}function ir(e){const i=rr(e),l=me,c=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],u={beginKeywords:"namespace",end:/\{/,excludeEnd:!0,contains:[i.exports.CLASS_REFERENCE]},n={beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:{keyword:"interface extends",built_in:c},contains:[i.exports.CLASS_REFERENCE]},t={className:"meta",relevance:10,begin:/^\s*['"]use strict['"]/},r=["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"],a={$pattern:me,keyword:gt.concat(r),literal:ht,built_in:_t.concat(c),"variable.language":vt},o={className:"meta",begin:"@"+l},s=(d,g,p)=>{const b=d.contains.findIndex(_=>_.label===g);if(b===-1)throw new Error("can not find mode to replace");d.contains.splice(b,1,p)};Object.assign(i.keywords,a),i.exports.PARAMS_CONTAINS.push(o),i.contains=i.contains.concat([o,u,n]),s(i,"shebang",e.SHEBANG()),s(i,"use_strict",t);const f=i.contains.find(d=>d.label==="func.def");return f.relevance=0,Object.assign(i,{name:"TypeScript",aliases:["ts","tsx"]}),i}X.registerLanguage("css",Vn),X.registerLanguage("xml",Wn),X.registerLanguage("markdown",qn),X.registerLanguage("javascript",er),X.registerLanguage("json",tr),X.registerLanguage("plaintext",nr),X.registerLanguage("typescript",ir);const Q="",Y="";var De=(e=>(e[e.removed=-1]="removed",e[e.equal=0]="equal",e[e.added=1]="added",e[e.disabled=2]="disabled",e))(De||{});const V=e=>De[e]?De[e]:"disabled",ar=e=>{const i=[],l={prev:0,current:0};return e.map(c=>{const u=c[0][1].replace(/\n$/,"").split(` 7 | `),n=c[1][1].replace(/\n$/,"").split(` 8 | `),t=Math.max(u.length,n.length);for(let r=0;r{const i=[];let l=0;return e.map(c=>{const u=c[0][1].replace(/\n$/,"").split(` 9 | `),n=c[1][1].replace(/\n$/,"").split(` 10 | `);u.map(t=>{V(c[0][0])==="removed"&&i.push([{type:V(c[0][0]),lineNum:void 0,value:t}])}),n.map(t=>{V(c[1][0])!=="disabled"&&(l+=1,i.push([{type:V(c[1][0]),lineNum:l,value:t}]))})}),i},or=(e,i,l)=>{function c(n,t){const r=new ke.exports.diff_match_patch,a=r.diff_linesToChars_(n,t),o=a.chars1,s=a.chars2,f=a.lineArray,d=r.diff_main(o,s,!1);return r.diff_charsToLines_(d,f),d}const u=c(i,l).reduce((n,t)=>{const r=V(t[0]);if(r==="equal"&&n.push([t]),r==="removed"&&n.push([t]),r==="added"){const a=n.length&&n[n.length-1][0]?n[n.length-1][0]:null;a&&V(a[0])==="removed"?n[n.length-1].push(t):n.push([t])}return n},[]);return u.map(n=>{if(n.length>1)return;const t=V(n[0][0]);t==="added"?n.unshift([2,""]):t==="removed"?n.push([2,""]):t==="equal"&&n.push([...n[0]])}),e==="split"?ar(u):e==="unified"?sr(u):[]},lr=(e,i)=>{const l=new ke.exports.diff_match_patch,c=l.diff_main(e,i);return l.diff_cleanupSemantic(c),c.filter(u=>V(u[0])!=="removed").map(u=>V(u[0])==="added"?`${Q}${u[1]}${Y}`:u[1]).join("")},cr=({highlightCode:e,language:i,code:l})=>{if(!l.match(new RegExp(`(${Q}|${Y})`,"g"))){e.value=X.highlight(l,{language:i}).value;return}let u=l;const n=l.replace(new RegExp(`(${Q}|${Y})`,"g"),"");let t=document.createElement("div");t.innerHTML=X.highlight(n,{language:i}).value;let r=!1;const a=f=>{f.childNodes.forEach(d=>{if(d.nodeType===1&&a(d),d.nodeType===3){if(!d.textContent)return;let g=d.textContent,p="";for(r&&(p+=Q);g.length;){if(u.startsWith(Q)){u=u.slice(Q.length),p+=Q,r=!0;continue}if(u.startsWith(Y)){u=u.slice(Y.length),p+=Y,r=!1;continue}const b=u.match(new RegExp(`(${Q}|${Y})`)),_=b&&b.index?b.index:u.length,w=Math.min(_,g.length);p+=u.substring(0,w),u=u.slice(w),g=g.slice(w)}r&&(p+=Y),d.textContent=p}})};a(t);const o=Q.replace("<","<").replace(">",">"),s=Y.replace("<","<").replace(">",">");e.value=t.innerHTML.replace(new RegExp(o,"g"),'').replace(new RegExp(s,"g"),""),t=null},fr=(e,i,l)=>{const c=h.ref([]),u=h.ref([]),n=h.computed(()=>u.value.filter(r=>e.folding?!r.foldable&&r.visible:r.visible));return Ze([()=>e.mode,()=>e.prev,()=>e.current,()=>e.folding],()=>{const r=or(e.mode,e.prev,e.current);c.value=r,u.value.splice(c.value.length),c.value.map((a,o)=>{var g;const s=u.value[o],f=e.folding&&a[0].type==="equal"&&((g=c.value[o-1])==null?void 0:g[0].type)==="equal",d={index:o,foldable:f,visible:!0};l.value?u.value[o]=At(we({},d),{visible:(s==null?void 0:s.visible)||!1,top:(s==null?void 0:s.top)||void 0,height:(s==null?void 0:s.height)||l.value.lineMinHeight}):u.value[o]=we({},d)})},{debounce:e.inputDelay,immediate:!0}),{meta:u,render:c,list:n}},dr=(e,i,l,c)=>{const u=h.computed(()=>l.value?c.value.reduce((r,a)=>(a.top=r,a.foldable?r:r+a.height),0)+"px":void 0),n=()=>{if(!i.value||!l.value)return;const t=i.value.scrollTop,r=l.value.height,a=t-1.5*r,o=t+r+1.5*r;c.value.reduce((s,f)=>(s>=a&&s<=o?f.visible=!0:f.visible=!1,f.top=s,f.foldable?s:s+f.height),0)};return Ze([()=>e.mode,()=>e.prev,()=>e.current,()=>e.folding],()=>h.nextTick(n),{debounce:e.inputDelay,immediate:!0}),h.onMounted(()=>{var t;!l.value||(t=i.value)==null||t.addEventListener("scroll",ce(n,l.value.delay))}),h.onBeforeUnmount(()=>{var t;!l.value||(t=i.value)==null||t.removeEventListener("scroll",ce(n,l.value.delay))}),h.watch(l,(t,r)=>{var a,o;!r&&t&&((a=i.value)==null||a.addEventListener("scroll",ce(n,t.delay))),r&&!t&&((o=i.value)==null||o.removeEventListener("scroll",ce(n,r.delay)))}),{minHeight:u}};var Ie=(e,i)=>{const l=e.__vccOpts||e;for(const[c,u]of i)l[c]=u;return l};const ur=h.defineComponent({props:{language:{type:String,required:!0},code:{type:String,required:!0},scrollOptions:{type:[Boolean,Object],default:!1}},emits:["rendered"],setup(e,{emit:i}){const l=h.ref("");return h.onMounted(()=>{h.watch([()=>e.language,()=>e.code],()=>{cr({highlightCode:l,language:e.language,code:e.code}),h.nextTick(()=>i("rendered"))},{immediate:!0}),h.watch([()=>e.scrollOptions],()=>{h.nextTick(()=>i("rendered"))},{deep:!0})}),{highlightCode:l}}}),gr=["innerHTML"];function hr(e,i,l,c,u,n){return h.openBlock(),h.createElementBlock("pre",null,[h.createElementVNode("code",{class:"hljs",innerHTML:e.highlightCode},null,8,gr)])}var pr=Ie(ur,[["render",hr]]);const br=h.defineComponent({components:{Code:pr},props:{mode:{type:String,required:!0},folding:{type:Boolean,default:!1},language:{type:String,required:!0},meta:{type:Object,required:!0},render:{type:Object,required:!0},scrollOptions:{type:[Boolean,Object],default:!1}},setup(e,{emit:i}){const l=h.ref(null),c=h.computed(()=>{if(!!e.scrollOptions)return{position:"absolute",left:0,top:0,transform:`translate3d(0, ${e.meta.top}px, 0)`,minHeight:e.scrollOptions.lineMinHeight+"px"}}),u=h.computed(()=>e.folding&&e.render[0].type==="equal"),n=(r,a,o)=>{if(!r.value)return` 11 | `;if(typeof a=="undefined"||typeof o=="undefined"||!r.chkWords)return r.value;const s=a[o===0?1:0];return s.value?lr(s.value,r.value):r.value},t=()=>{!l.value||e.meta.height===l.value.offsetHeight||i("setLineHeight",e.meta.index,l.value.offsetHeight)};return e.scrollOptions&&Kt(l,ce(()=>{!l.value||e.meta.height===l.value.offsetHeight||i("setLineHeight",e.meta.index,l.value.offsetHeight)},e.scrollOptions.delay)),{line:l,isFoldLine:u,rendered:t,rowStyle:c,setCode:n}}}),mr=h.createElementVNode("div",{class:"lineNum vue-diff-cell-fold"},null,-1),vr=h.createElementVNode("div",{class:"code vue-diff-cell-fold"},null,-1),_r=h.createElementVNode("div",{class:"lineNum vue-diff-cell-fold"},null,-1),yr=h.createElementVNode("div",{class:"code vue-diff-cell-fold"},null,-1);function wr(e,i,l,c,u,n){const t=h.resolveComponent("Code");return h.openBlock(),h.createElementBlock("div",{ref:"line",class:h.normalizeClass(["vue-diff-row",`vue-diff-row-${e.mode}`]),style:h.normalizeStyle(e.rowStyle)},[e.mode==="split"?(h.openBlock(!0),h.createElementBlock(h.Fragment,{key:0},h.renderList(e.render,(r,a)=>(h.openBlock(),h.createElementBlock(h.Fragment,{key:a},[e.isFoldLine?(h.openBlock(),h.createElementBlock(h.Fragment,{key:0},[mr,vr],64)):(h.openBlock(),h.createElementBlock(h.Fragment,{key:1},[h.createElementVNode("div",{class:h.normalizeClass(["lineNum",`vue-diff-cell-${r.type}`])},h.toDisplayString(r.lineNum),3),h.createElementVNode("div",{class:h.normalizeClass(["code",`vue-diff-cell-${r.type}`])},[h.createVNode(t,{language:e.language,code:e.setCode(r,e.render,a),scrollOptions:e.scrollOptions,onRendered:e.rendered},null,8,["language","code","scrollOptions","onRendered"])],2)],64))],64))),128)):h.createCommentVNode("",!0),e.mode==="unified"?(h.openBlock(),h.createElementBlock(h.Fragment,{key:1},[e.isFoldLine?(h.openBlock(),h.createElementBlock(h.Fragment,{key:0},[_r,yr],64)):(h.openBlock(),h.createElementBlock(h.Fragment,{key:1},[h.createElementVNode("div",{class:h.normalizeClass(["lineNum",`vue-diff-cell-${e.render[0].type}`])},h.toDisplayString(e.render[0].lineNum),3),h.createElementVNode("div",{class:h.normalizeClass(["code",`vue-diff-cell-${e.render[0].type}`])},[h.createVNode(t,{language:e.language,code:e.setCode(e.render[0]),scrollOptions:e.scrollOptions,onRendered:e.rendered},null,8,["language","code","scrollOptions","onRendered"])],2)],64))],64)):h.createCommentVNode("",!0)],6)}var Er=Ie(br,[["render",wr]]);const xr=h.defineComponent({components:{Line:Er},props:{mode:{type:String,default:"split"},theme:{type:String,default:"dark"},language:{type:String,default:"plaintext"},prev:{type:String,default:""},current:{type:String,default:""},folding:{type:Boolean,default:!1},inputDelay:{type:Number,default:0},virtualScroll:{type:[Boolean,Object],default:!1}},setup(e){const i=h.ref(null),l=h.computed(()=>e.virtualScroll?we({height:500,lineMinHeight:24,delay:100},typeof e.virtualScroll=="object"?h.toRaw(e.virtualScroll):{}):!1),{meta:c,render:u,list:n}=fr(e,i,l),{minHeight:t}=dr(e,i,l,c);return{list:n,meta:c,minHeight:t,render:u,scrollOptions:l,setLineHeight:(a,o)=>{c.value[a]&&c.value[a].height!==o&&(c.value[a].height=o)},viewer:i}}});function kr(e,i,l,c,u,n){const t=h.resolveComponent("Line");return h.openBlock(),h.createElementBlock("div",{class:h.normalizeClass(["vue-diff-wrapper",`vue-diff-mode-${e.mode} vue-diff-theme-${e.theme}`])},[h.createElementVNode("div",{ref:"viewer",class:"vue-diff-viewer",style:h.normalizeStyle({height:e.scrollOptions?e.scrollOptions.height+"px":void 0})},[h.createElementVNode("div",{class:"vue-diff-viewer-inner",style:h.normalizeStyle({minHeight:e.minHeight})},[(h.openBlock(!0),h.createElementBlock(h.Fragment,null,h.renderList(e.list,(r,a)=>(h.openBlock(),h.createBlock(t,{key:a,mode:e.mode,folding:e.folding,language:e.language,meta:e.meta[r.index],render:e.render[r.index],scrollOptions:e.scrollOptions,onSetLineHeight:e.setLineHeight},null,8,["mode","folding","language","meta","render","scrollOptions","onSetLineHeight"]))),128))],4)],4)],2)}var yt=Ie(xr,[["render",kr]]),$r="",Nr={install:(e,i={})=>{const{componentName:l="Diff"}=i;e.component(l,yt)},hljs:X};H.Diff=yt,H.default=Nr,Object.defineProperties(H,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); 12 | --------------------------------------------------------------------------------