mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-17 23:45:59 +00:00
Merge branch 'master' of https://github.com/dbgate/dbgate
This commit is contained in:
@@ -61,6 +61,7 @@
|
||||
"date-fns": "^4.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"fuzzy": "^0.1.3",
|
||||
"highlight.js": "^11.11.1",
|
||||
"interval-operations": "^1.0.7",
|
||||
"leaflet": "^1.8.0",
|
||||
"wellknown": "^0.5.0"
|
||||
|
||||
9
packages/web/src/celldata/XmlCellView.svelte
Normal file
9
packages/web/src/celldata/XmlCellView.svelte
Normal file
@@ -0,0 +1,9 @@
|
||||
<script lang="ts">
|
||||
import XmlHighlighter from './XmlHighlighter.svelte';
|
||||
|
||||
export let selection;
|
||||
</script>
|
||||
|
||||
{#each selection as cell}
|
||||
<XmlHighlighter code={cell.value} />
|
||||
{/each}
|
||||
42
packages/web/src/celldata/XmlHighlighter.svelte
Normal file
42
packages/web/src/celldata/XmlHighlighter.svelte
Normal file
@@ -0,0 +1,42 @@
|
||||
<script>
|
||||
import hljs from 'highlight.js/lib/core';
|
||||
import xmlGrammar from './xmlGrammar';
|
||||
import formatXml from './formatXml';
|
||||
import { afterUpdate, onMount } from 'svelte';
|
||||
|
||||
import 'highlight.js/styles/vs.css';
|
||||
|
||||
export let code = '';
|
||||
|
||||
$: formattedCode = formatXml(code);
|
||||
|
||||
onMount(() => {
|
||||
hljs.registerLanguage('xml', xmlGrammar);
|
||||
});
|
||||
|
||||
afterUpdate(() => {
|
||||
if (codeBlock) {
|
||||
hljs.highlightElement(codeBlock);
|
||||
}
|
||||
});
|
||||
|
||||
let codeBlock;
|
||||
</script>
|
||||
|
||||
{#key formattedCode}
|
||||
<pre><code bind:this={codeBlock}>{formattedCode}</code></pre>
|
||||
{/key}
|
||||
|
||||
<style>
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
code {
|
||||
display: block;
|
||||
padding: 0.5em;
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
24
packages/web/src/celldata/formatXml.ts
Normal file
24
packages/web/src/celldata/formatXml.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export default function formatXml(xml: string): string {
|
||||
if (typeof xml !== 'string') return '';
|
||||
|
||||
xml = xml.replace(/>\s*</g, '><');
|
||||
|
||||
let formatted = '';
|
||||
let indent = 0;
|
||||
|
||||
const tags = xml.split(/(<.*?>)/g).filter(s => s.trim());
|
||||
|
||||
for (let tag of tags) {
|
||||
if (tag.startsWith('</')) {
|
||||
indent--;
|
||||
formatted += '\n' + ' '.repeat(indent) + tag;
|
||||
} else if (tag.startsWith('<') && !tag.endsWith('/>') && !tag.startsWith('<?')) {
|
||||
formatted += '\n' + ' '.repeat(indent) + tag;
|
||||
indent++;
|
||||
} else {
|
||||
formatted += '\n' + ' '.repeat(indent) + tag;
|
||||
}
|
||||
}
|
||||
|
||||
return formatted.trim();
|
||||
}
|
||||
205
packages/web/src/celldata/xmlGrammar.js
Normal file
205
packages/web/src/celldata/xmlGrammar.js
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Language: HTML, XML
|
||||
Website: https://www.w3.org/XML/
|
||||
Category: common, web
|
||||
Audit: 2020
|
||||
*/
|
||||
|
||||
export default function (hljs) {
|
||||
const regex = hljs.regex;
|
||||
// XML names can have the following additional letters: https://www.w3.org/TR/xml/#NT-NameChar
|
||||
// OTHER_NAME_CHARS = /[:\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]/;
|
||||
// Element names start with NAME_START_CHAR followed by optional other Unicode letters, ASCII digits, hyphens, underscores, and periods
|
||||
// const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/);;
|
||||
// const XML_IDENT_RE = /[A-Z_a-z:\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]+/;
|
||||
// const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/);
|
||||
// however, to cater for performance and more Unicode support rely simply on the Unicode letter class
|
||||
const TAG_NAME_RE = regex.concat(/[\p{L}_]/u, regex.optional(/[\p{L}0-9_.-]*:/u), /[\p{L}0-9_.-]*/u);
|
||||
const XML_IDENT_RE = /[\p{L}0-9._:-]+/u;
|
||||
const XML_ENTITIES = {
|
||||
className: 'symbol',
|
||||
begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/,
|
||||
};
|
||||
const XML_META_KEYWORDS = {
|
||||
begin: /\s/,
|
||||
contains: [
|
||||
{
|
||||
className: 'keyword',
|
||||
begin: /#?[a-z_][a-z1-9_-]+/,
|
||||
illegal: /\n/,
|
||||
},
|
||||
],
|
||||
};
|
||||
const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, {
|
||||
begin: /\(/,
|
||||
end: /\)/,
|
||||
});
|
||||
const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, { className: 'string' });
|
||||
const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' });
|
||||
const TAG_INTERNALS = {
|
||||
endsWithParent: true,
|
||||
illegal: /</,
|
||||
relevance: 0,
|
||||
contains: [
|
||||
{
|
||||
className: 'attr',
|
||||
begin: XML_IDENT_RE,
|
||||
relevance: 0,
|
||||
},
|
||||
{
|
||||
begin: /=\s*/,
|
||||
relevance: 0,
|
||||
contains: [
|
||||
{
|
||||
className: 'string',
|
||||
endsParent: true,
|
||||
variants: [
|
||||
{
|
||||
begin: /"/,
|
||||
end: /"/,
|
||||
contains: [XML_ENTITIES],
|
||||
},
|
||||
{
|
||||
begin: /'/,
|
||||
end: /'/,
|
||||
contains: [XML_ENTITIES],
|
||||
},
|
||||
{ begin: /[^\s"'=<>`]+/ },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
return {
|
||||
name: 'HTML, XML',
|
||||
aliases: ['html', 'xhtml', 'rss', 'atom', 'xjb', 'xsd', 'xsl', 'plist', 'wsf', 'svg'],
|
||||
case_insensitive: true,
|
||||
unicodeRegex: true,
|
||||
contains: [
|
||||
{
|
||||
className: 'meta',
|
||||
begin: /<![a-z]/,
|
||||
end: />/,
|
||||
relevance: 10,
|
||||
contains: [
|
||||
XML_META_KEYWORDS,
|
||||
QUOTE_META_STRING_MODE,
|
||||
APOS_META_STRING_MODE,
|
||||
XML_META_PAR_KEYWORDS,
|
||||
{
|
||||
begin: /\[/,
|
||||
end: /\]/,
|
||||
contains: [
|
||||
{
|
||||
className: 'meta',
|
||||
begin: /<![a-z]/,
|
||||
end: />/,
|
||||
contains: [XML_META_KEYWORDS, XML_META_PAR_KEYWORDS, QUOTE_META_STRING_MODE, APOS_META_STRING_MODE],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
hljs.COMMENT(/<!--/, /-->/, { relevance: 10 }),
|
||||
{
|
||||
begin: /<!\[CDATA\[/,
|
||||
end: /\]\]>/,
|
||||
relevance: 10,
|
||||
},
|
||||
XML_ENTITIES,
|
||||
// xml processing instructions
|
||||
{
|
||||
className: 'meta',
|
||||
end: /\?>/,
|
||||
variants: [
|
||||
{
|
||||
begin: /<\?xml/,
|
||||
relevance: 10,
|
||||
contains: [QUOTE_META_STRING_MODE],
|
||||
},
|
||||
{
|
||||
begin: /<\?[a-z][a-z0-9]+/,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
className: 'tag',
|
||||
/*
|
||||
The lookahead pattern (?=...) ensures that 'begin' only matches
|
||||
'<style' as a single word, followed by a whitespace or an
|
||||
ending bracket.
|
||||
*/
|
||||
begin: /<style(?=\s|>)/,
|
||||
end: />/,
|
||||
keywords: { name: 'style' },
|
||||
contains: [TAG_INTERNALS],
|
||||
starts: {
|
||||
end: /<\/style>/,
|
||||
returnEnd: true,
|
||||
subLanguage: ['css', 'xml'],
|
||||
},
|
||||
},
|
||||
{
|
||||
className: 'tag',
|
||||
// See the comment in the <style tag about the lookahead pattern
|
||||
begin: /<script(?=\s|>)/,
|
||||
end: />/,
|
||||
keywords: { name: 'script' },
|
||||
contains: [TAG_INTERNALS],
|
||||
starts: {
|
||||
end: /<\/script>/,
|
||||
returnEnd: true,
|
||||
subLanguage: ['javascript', 'handlebars', 'xml'],
|
||||
},
|
||||
},
|
||||
// we need this for now for jSX
|
||||
{
|
||||
className: 'tag',
|
||||
begin: /<>|<\/>/,
|
||||
},
|
||||
// open tag
|
||||
{
|
||||
className: 'tag',
|
||||
begin: regex.concat(
|
||||
/</,
|
||||
regex.lookahead(
|
||||
regex.concat(
|
||||
TAG_NAME_RE,
|
||||
// <tag/>
|
||||
// <tag>
|
||||
// <tag ...
|
||||
regex.either(/\/>/, />/, /\s/)
|
||||
)
|
||||
)
|
||||
),
|
||||
end: /\/?>/,
|
||||
contains: [
|
||||
{
|
||||
className: 'name',
|
||||
begin: TAG_NAME_RE,
|
||||
relevance: 0,
|
||||
starts: TAG_INTERNALS,
|
||||
},
|
||||
],
|
||||
},
|
||||
// close tag
|
||||
{
|
||||
className: 'tag',
|
||||
begin: regex.concat(/<\//, regex.lookahead(regex.concat(TAG_NAME_RE, />/))),
|
||||
contains: [
|
||||
{
|
||||
className: 'name',
|
||||
begin: TAG_NAME_RE,
|
||||
relevance: 0,
|
||||
},
|
||||
{
|
||||
begin: />/,
|
||||
relevance: 0,
|
||||
endsParent: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -44,6 +44,12 @@
|
||||
component: HtmlCellView,
|
||||
single: false,
|
||||
},
|
||||
{
|
||||
type: 'xml',
|
||||
title: 'XML',
|
||||
component: XmlCellView,
|
||||
single: false,
|
||||
},
|
||||
{
|
||||
type: 'map',
|
||||
title: 'Map',
|
||||
@@ -68,6 +74,9 @@
|
||||
if (_.isPlainObject(value) || _.isArray(value)) {
|
||||
return 'json';
|
||||
}
|
||||
if (typeof value === 'string' && value.startsWith('<') && value.endsWith('>')) {
|
||||
return 'xml';
|
||||
}
|
||||
return 'textWrap';
|
||||
}
|
||||
|
||||
@@ -91,6 +100,7 @@
|
||||
import { selectedCellsCallback } from '../stores';
|
||||
import WidgetTitle from './WidgetTitle.svelte';
|
||||
import JsonExpandedCellView from '../celldata/JsonExpandedCellView.svelte';
|
||||
import XmlCellView from '../celldata/XmlCellView.svelte';
|
||||
|
||||
let selectedFormatType = 'autodetect';
|
||||
|
||||
|
||||
@@ -5917,6 +5917,11 @@ highlight.js@11.9.0:
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
|
||||
integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
|
||||
|
||||
highlight.js@^11.11.1:
|
||||
version "11.11.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.11.1.tgz#fca06fa0e5aeecf6c4d437239135fabc15213585"
|
||||
integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==
|
||||
|
||||
hogan.js@3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hogan.js/-/hogan.js-3.0.2.tgz#4cd9e1abd4294146e7679e41d7898732b02c7bfd"
|
||||
|
||||
Reference in New Issue
Block a user