From 4e1b51b8461c9a8e6a5a8feccc2a5f15e9f0b6a9 Mon Sep 17 00:00:00 2001 From: Richie Varghese Date: Sat, 13 Dec 2025 11:03:22 +0530 Subject: [PATCH 1/3] feat: Add AI assistance, markdown support for notebooks, and refactor SQL utilities. --- CHANGELOG.md | 70 ++ MARKETPLACE.md | 1 + README.md | 8 + docs/index.html | 2 +- resources/highlight.css | 10 + resources/highlight.min.js | 1213 +++++++++++++++++++++++++++++ resources/marked.min.js | 69 ++ src/commands/aiAssist.ts | 437 +---------- src/commands/helper.ts | 1018 +----------------------- src/commands/sql/helper.ts | 1018 ++++++++++++++++++++++++ src/commands/sql/index.ts | 1 + src/notebookProvider.ts | 15 +- src/providers/ChatViewProvider.ts | 122 ++- src/providers/chat/AiService.ts | 159 ++-- src/providers/chat/webviewHtml.ts | 472 ++++++----- 15 files changed, 2909 insertions(+), 1706 deletions(-) create mode 100644 resources/highlight.css create mode 100644 resources/highlight.min.js create mode 100644 resources/marked.min.js create mode 100644 src/commands/sql/helper.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6224277..bcded28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,76 @@ All notable changes to the PostgreSQL Explorer extension will be documented in t The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.5.3] - 2025-12-07 + +### Fixed +- Minor bug fixes and stability improvements +- Fixed linting errors and type issues across command files + +--- + +## [0.5.2] - 2025-12-06 + +### Changed +- **SQL Template Refactoring**: Extracted embedded SQL from TypeScript command files into dedicated template modules + - Created `src/commands/sql/` directory with 13 specialized SQL template modules + - Modules: columns, constraints, extensions, foreignTables, functions, indexes, materializedViews, schema, tables, types, usersRoles, views + - Improved code maintainability and separation of concerns + +--- + +## [0.5.1] - 2025-12-05 + +### Changed +- **Helper Abstractions Refactoring**: Refactored command files to use `getDatabaseConnection` and `NotebookBuilder` methods + - Updated `tables.ts`, `database.ts`, and `aiAssist.ts` to use new helper abstractions + - Improved code reusability and consistency across commands + +--- + +## [0.5.0] - 2025-12-05 + +### Added +- **Enhanced Table Renderer**: New `renderer_v2.ts` with improved table output styling +- **Export Data Functionality**: Export query results to CSV, JSON, and Excel formats +- **Column Operations**: Enhanced column context menu with copy, scripts, and statistics +- **Constraint Operations**: Enhanced constraint management with validation and dependencies +- **Index Operations**: Enhanced index management with usage analysis and maintenance scripts + +### Fixed +- Fixed persistent renderer cache issues +- Fixed excessive row height in table output +- Fixed chart initialization in dashboard + +--- + +## [0.4.0] - 2025-12-03 + +### Added +- **Inline Create Buttons**: Added "+" buttons for creating objects directly from category nodes + - Tables, Views, Functions, Types, Materialized Views, Foreign Tables, Roles, Extensions, Schemas, Databases +- **Enhanced Script Generation**: Improved CREATE script generation for indexes +- **Column Context Menu**: Added comprehensive column operations menu + +### Fixed +- Fixed connection UI button functionality +- Fixed index creation script visibility in context menu + +--- + +## [0.3.0] - 2025-12-01 + +### Added +- **Comprehensive Test Coverage**: Added unit tests for NotebookKernel with improved coverage +- **Serialization Error Handling**: Improved handling of serialization errors in query results + +### Changed +- Improved dashboard UI with pastel colors and modern styling +- Enhanced chart visualizations with area charts and translucent effects +- Fixed Cancel and Kill buttons in active queries table + +--- + ## [0.2.3] - 2025-11-29 ### Added diff --git a/MARKETPLACE.md b/MARKETPLACE.md index 8154e2a..e7ec45d 100644 --- a/MARKETPLACE.md +++ b/MARKETPLACE.md @@ -41,6 +41,7 @@ | πŸ› οΈ **Object Operations** | Full CRUD operations, scripts, VACUUM, ANALYZE, REINDEX | | πŸ€– **AI-Powered** | GitHub Copilot, OpenAI, Anthropic, and Google Gemini integration | | ⌨️ **Developer Tools** | IntelliSense, keyboard shortcuts, PSQL terminal access | +| πŸ“€ **Export Data** | Export query results to CSV, JSON, or Excel formats | --- diff --git a/README.md b/README.md index 9851d2b..5d5a91b 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ A comprehensive PostgreSQL database management extension featuring interactive S - 🌳 **Database Explorer** β€” Browse tables, views, functions, types - πŸ› οΈ **Object Operations** β€” CRUD, scripts, VACUUM, ANALYZE, REINDEX - πŸ€– **AI-Powered** β€” GitHub Copilot, OpenAI, Anthropic, Gemini +- πŸ“€ **Export Data** β€” Export results to CSV, JSON, or Excel --- @@ -60,6 +61,13 @@ yape/ β”‚ β”‚ β”œβ”€β”€ functions.ts # Function operations β”‚ β”‚ β”œβ”€β”€ connection.ts # Connection commands β”‚ β”‚ β”œβ”€β”€ notebook.ts # Notebook commands +β”‚ β”‚ β”œβ”€β”€ helper.ts # Shared helper utilities +β”‚ β”‚ β”œβ”€β”€ sql/ # SQL template modules +β”‚ β”‚ β”‚ β”œβ”€β”€ tables.ts # Table SQL templates +β”‚ β”‚ β”‚ β”œβ”€β”€ views.ts # View SQL templates +β”‚ β”‚ β”‚ β”œβ”€β”€ functions.ts # Function SQL templates +β”‚ β”‚ β”‚ β”œβ”€β”€ indexes.ts # Index SQL templates +β”‚ β”‚ β”‚ └── ... # Other SQL templates β”‚ β”‚ └── ... β”‚ β”œβ”€β”€ providers/ # VS Code providers β”‚ β”‚ β”œβ”€β”€ DatabaseTreeProvider.ts # Tree view provider diff --git a/docs/index.html b/docs/index.html index 91c9994..4bc8a18 100644 --- a/docs/index.html +++ b/docs/index.html @@ -51,7 +51,7 @@
VS Code Marketplace - 0.4.0 + 0.5.3
diff --git a/resources/highlight.css b/resources/highlight.css new file mode 100644 index 0000000..03b6da8 --- /dev/null +++ b/resources/highlight.css @@ -0,0 +1,10 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*! + Theme: GitHub Dark + Description: Dark theme as seen on github.com + Author: github.com + Maintainer: @Hirse + Updated: 2021-05-15 + + Outdated base version: https://github.com/primer/github-syntax-dark + Current colors taken from GitHub's CSS +*/.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c} \ No newline at end of file diff --git a/resources/highlight.min.js b/resources/highlight.min.js new file mode 100644 index 0000000..5d699ae --- /dev/null +++ b/resources/highlight.min.js @@ -0,0 +1,1213 @@ +/*! + Highlight.js v11.9.0 (git: f47103d4f1) + (c) 2006-2023 undefined and other contributors + License: BSD-3-Clause + */ +var hljs=function(){"use strict";function e(n){ +return n instanceof Map?n.clear=n.delete=n.set=()=>{ +throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{ +throw Error("set is read-only") +}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{ +const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a) +})),n}class n{constructor(e){ +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} +ignoreMatch(){this.isMatchIgnored=!0}}function t(e){ +return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") +}function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] +;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope +;class r{constructor(e,n){ +this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ +this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{ +if(e.startsWith("language:"))return e.replace("language:","language-") +;if(e.includes(".")){const t=e.split(".") +;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") +}return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)} +closeNode(e){i(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ +this.buffer+=``}}const s=(e={})=>{const n={children:[]} +;return Object.assign(n,e),n};class o{constructor(){ +this.rootNode=s(),this.stack=[this.rootNode]}get top(){ +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ +this.top.children.push(e)}openNode(e){const n=s({scope:e}) +;this.add(n),this.stack.push(n)}closeNode(){ +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ +return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), +n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ +o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e} +addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ +this.closeNode()}__addSublanguage(e,n){const t=e.root +;n&&(t.scope="language:"+n),this.add(t)}toHTML(){ +return new r(this,this.options).value()}finalize(){ +return this.closeAllNodes(),!0}}function c(e){ +return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")} +function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")} +function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{ +const n=e[e.length-1] +;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} +})(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"} +function p(e){return RegExp(e.toString()+"|").exec("").length-1} +const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ +;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t +;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break} +i+=a.substring(0,e.index), +a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], +"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} +const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={ +begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'", +illegal:"\\n",contains:[v]},k={scope:"string",begin:'"',end:'"',illegal:"\\n", +contains:[v]},x=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n, +contains:[]},t);i.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 r=m("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 i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i +},M=x("//","$"),S=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({ +__proto__:null,APOS_STRING_MODE:O,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{ +scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:x, +C_BLOCK_COMMENT_MODE:S,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number", +begin:N,relevance:0},C_NUMBER_RE:N,END_SAME_AS_BEGIN:e=>Object.assign(e,{ +"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:A,IDENT_RE:f, +MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0}, +NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y, +PHRASAL_WORDS_MODE:{ +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/ +},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, +end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}, +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", +SHEBANG:(e={})=>{const n=/^#![ ]*\// +;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n, +end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, +TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E, +UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){ +"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){ +void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){ +n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", +e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, +void 0===e.relevance&&(e.relevance=0))}function I(e,n){ +Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){ +if(e.match){ +if(e.begin||e.end)throw Error("begin & end are not supported with match") +;e.begin=e.match,delete e.match}}function B(e,n){ +void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return +;if(e.starts)throw Error("beforeMatch cannot be used with starts") +;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] +})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={ +relevance:0,contains:[Object.assign(t,{endsParent:!0})] +},e.relevance=0,delete t.beforeMatch +},z=["of","and","for","in","not","or","if","then","parent","list","value"],F="keyword" +;function U(e,n,t=F){const a=Object.create(null) +;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ +Object.assign(a,U(e[t],n,t))})),a;function i(e,t){ +n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") +;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){ +return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ +console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{ +P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) +},G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={} +;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1]) +;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope +}),(e=>{if(Array.isArray(e.begin)){ +if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), +G +;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), +G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{ +if(Array.isArray(e.end)){ +if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), +G +;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), +G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){ +function n(n,t){ +return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) +}class t{constructor(){ +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} +addRule(e,n){ +n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), +this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) +;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|" +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex +;const n=this.matcherRe.exec(e);if(!n)return null +;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] +;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){ +this.rules=[],this.multiRegexes=[], +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ +if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t +;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), +n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ +this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ +const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex +;let t=n.exec(e) +;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ +const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} +return t&&(this.regexIndex+=t.position+1, +this.regexIndex===this.count&&this.considerAll()),t}} +if(e.compilerExtensions||(e.compilerExtensions=[]), +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") +;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r +;if(r.isCompiled)return o +;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), +r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), +l=r.keywords.$pattern, +delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)), +o.keywordPatternRe=n(l,!0), +s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), +r.end&&(o.endRe=n(o.end)), +o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), +r.illegal&&(o.illegalRe=n(r.illegal)), +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{ +variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{ +starts:e.starts?a(e.starts):null +}):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) +})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i +;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" +}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" +}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ +return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ +constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} +const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{ +const a=Object.create(null),i=Object.create(null),r=[];let s=!0 +;const o="Could not find the language '{}', did you forget to load/include a language module?",c={ +disableAutodetect:!0,name:"Plain text",contains:[]};let p={ +ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", +cssSelector:"pre code",languages:null,__emitter:l};function _(e){ +return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" +;"object"==typeof n?(a=e, +t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."), +q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), +i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r) +;const s=r.result?r.result:f(r.language,r.code,t) +;return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){ +const l=Object.create(null);function c(){if(!x.keywords)return void S.addText(A) +;let e=0;x.keywordPatternRe.lastIndex=0;let n=x.keywordPatternRe.exec(A),t="" +;for(;n;){t+=A.substring(e,n.index) +;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,x.keywords[a]);if(r){ +const[e,a]=r +;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{ +const t=w.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0] +;e=x.keywordPatternRe.lastIndex,n=x.keywordPatternRe.exec(A)}var a +;t+=A.substring(e),S.addText(t)}function d(){null!=x.subLanguage?(()=>{ +if(""===A)return;let e=null;if("string"==typeof x.subLanguage){ +if(!a[x.subLanguage])return void S.addText(A) +;e=f(x.subLanguage,A,!0,M[x.subLanguage]),M[x.subLanguage]=e._top +}else e=E(A,x.subLanguage.length?x.subLanguage:null) +;x.relevance>0&&(C+=e.relevance),S.__addSublanguage(e._emitter,e.language) +})():c(),A=""}function g(e,n){ +""!==e&&(S.startScope(n),S.addText(e),S.endScope())}function u(e,n){let t=1 +;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue} +const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(A=i,c(),A=""),t++}} +function b(e,n){ +return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope), +e.beginScope&&(e.beginScope._wrap?(g(A,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), +A=""):e.beginScope._multi&&(u(e.beginScope,n),A="")),x=Object.create(e,{parent:{ +value:x}}),x}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n) +;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e) +;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){ +for(;e.endsParent&&e.parent;)e=e.parent;return e}} +if(e.endsWithParent)return m(e.parent,t,a)}function _(e){ +return 0===x.matcher.regexIndex?(A+=e[0],1):(D=!0,0)}function h(e){ +const n=e[0],a=t.substring(e.index),i=m(x,e,a);if(!i)return ee;const r=x +;x.endScope&&x.endScope._wrap?(d(), +g(n,x.endScope._wrap)):x.endScope&&x.endScope._multi?(d(), +u(x.endScope,e)):r.skip?A+=n:(r.returnEnd||r.excludeEnd||(A+=n), +d(),r.excludeEnd&&(A=n));do{ +x.scope&&S.closeNode(),x.skip||x.subLanguage||(C+=x.relevance),x=x.parent +}while(x!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length} +let y={};function N(a,r){const o=r&&r[0];if(A+=a,null==o)return d(),0 +;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){ +if(A+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) +;throw n.languageName=e,n.badRule=y.rule,n}return 1} +if(y=r,"begin"===r.type)return(e=>{ +const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]] +;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t) +;return a.skip?A+=t:(a.excludeBegin&&(A+=t), +d(),a.returnBegin||a.excludeBegin||(A=t)),b(a,e),a.returnBegin?0:t.length})(r) +;if("illegal"===r.type&&!i){ +const e=Error('Illegal lexeme "'+o+'" for mode "'+(x.scope||"")+'"') +;throw e.mode=x,e}if("end"===r.type){const e=h(r);if(e!==ee)return e} +if("illegal"===r.type&&""===o)return 1 +;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches") +;return A+=o,o.length}const w=v(e) +;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') +;const O=Q(w);let k="",x=r||O;const M={},S=new p.__emitter(p);(()=>{const e=[] +;for(let n=x;n!==w;n=n.parent)n.scope&&e.unshift(n.scope) +;e.forEach((e=>S.openNode(e)))})();let A="",C=0,T=0,R=0,D=!1;try{ +if(w.__emitTokens)w.__emitTokens(t,S);else{for(x.matcher.considerAll();;){ +R++,D?D=!1:x.matcher.considerAll(),x.matcher.lastIndex=T +;const e=x.matcher.exec(t);if(!e)break;const n=N(t.substring(T,e.index),e) +;T=e.index+n}N(t.substring(T))}return S.finalize(),k=S.toHTML(),{language:e, +value:k,relevance:C,illegal:!1,_emitter:S,_top:x}}catch(n){ +if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t), +illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T, +context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:k},_emitter:S};if(s)return{ +language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:x} +;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{ +const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)} +;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1))) +;i.unshift(t);const r=i.sort(((e,n)=>{ +if(e.relevance!==n.relevance)return n.relevance-e.relevance +;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 +;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s +;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{ +let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" +;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1]) +;return n||(H(o.replace("{}",t[1])), +H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} +return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return +;if(x("before:highlightElement",{el:e,language:t +}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) +;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), +console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), +console.warn("The element with unescaped HTML:"), +console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) +;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) +;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t +;e.classList.add("hljs"),e.classList.add("language-"+a) +})(e,t,r.language),e.result={language:r.language,re:r.relevance, +relevance:r.relevance},r.secondBest&&(e.secondBest={ +language:r.secondBest.language,relevance:r.secondBest.relevance +}),x("after:highlightElement",{el:e,result:r,text:a})}let N=!1;function w(){ +"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):N=!0 +}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} +function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ +i[e.toLowerCase()]=n}))}function k(e){const n=v(e) +;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{ +e[t]&&e[t](n)}))} +"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ +N&&w()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:w, +highlightElement:y, +highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"), +q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)}, +initHighlighting:()=>{ +w(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, +initHighlightingOnLoad:()=>{ +w(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") +},registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){ +if(K("Language definition for '{}' could not be registered.".replace("{}",e)), +!s)throw n;K(n),i=c} +i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&O(i.aliases,{ +languageName:e})},unregisterLanguage:e=>{delete a[e] +;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, +listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O, +autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{ +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ +e["before:highlightBlock"](Object.assign({block:n.el},n)) +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ +e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}, +removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{ +s=!1},t.safeMode=()=>{s=!0},t.versionString="11.9.0",t.regex={concat:b, +lookahead:d,either:m,optional:u,anyNumberOfTimes:g} +;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t +},te=ne({});te.newInstance=()=>ne({});var ae=te;const ie=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_-]*/} +}),re=["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"],se=["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"],oe=["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"],le=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ce=["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(),de=oe.concat(le) +;var ge="[0-9](_*[0-9])*",ue=`\\.(${ge})`,be="[0-9a-fA-F](_*[0-9a-fA-F])*",me={ +className:"number",variants:[{ +begin:`(\\b(${ge})((${ue})|\\.)?|(${ue}))[eE][+-]?(${ge})[fFdD]?\\b`},{ +begin:`\\b(${ge})((${ue})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ +begin:`(${ue})[fFdD]?\\b`},{begin:`\\b(${ge})[fFdD]\\b`},{ +begin:`\\b0[xX]((${be})\\.?|(${be})?\\.(${be}))[pP][+-]?(${ge})[fFdD]?\\b`},{ +begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${be})[lL]?\\b`},{ +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], +relevance:0};function pe(e,n,t){return-1===t?"":e.replace(n,(a=>pe(e,n,t-1)))} +const _e="[A-Za-z$_][0-9A-Za-z$_]*",he=["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"],fe=["true","false","null","undefined","NaN","Infinity"],Ee=["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"],ye=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],Ne=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],ve=[].concat(Ne,Ee,ye) +;function Oe(e){const n=e.regex,t=_e,a={begin:/<[A-Za-z0-9\\._:-]+/, +end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ +const t=e[0].length+e.index,a=e.input[t] +;if("<"===a||","===a)return void n.ignoreMatch();let i +;">"===a&&(((e,{after:n})=>{const t="",M={ +match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(x)], +keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]} +;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ +PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/, +contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ +label:"use_strict",className:"meta",relevance:10, +begin:/^\s*['"]use (strict|asm)['"]/ +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{ +className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{ +begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", +keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{ +className:"function",begin:x,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:i,contains:h}]}]},{begin:/,/,relevance:0},{match:/\s+/, +relevance:0},{variants:[{begin:"<>",end:""},{ +match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, +"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ +begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},N,{ +beginKeywords:"while if switch catch for"},{ +begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", +returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t, +className:"title.function"})]},{match:/\.\.\./,relevance:0},O,{match:"\\$"+t, +relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, +contains:[f]},w,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},E,k,{match:/\$[(.]/}]}} +const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Me=["init","self"].map(ke),Se=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Ce=["false","nil","true"],Te=["assignment","associativity","higherThan","left","lowerThan","none","right"],Re=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],De=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ie=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Le=m(Ie,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Be=b(Ie,Le,"*"),$e=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),ze=m($e,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b($e,ze,"*"),Ue=b(/[A-Z]/,ze,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Pe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] +;var Ke=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ +begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} +;Object.assign(t,{className:"variable",variants:[{ +begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ +className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={ +begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, +end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$?\(\(/, +end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] +},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 +}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, +contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ +name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, +keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], +literal:["true","false"], +built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] +},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{ +match:/\\"/},{className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}, +grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] +}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ +className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ +match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ +className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 +},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ +keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], +type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"], +literal:"true false NULL", +built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" +},b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ +begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ +begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], +relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, +keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, +end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] +}]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, +disableAutodetect:!0,illegal:"=]/,contains:[{ +beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, +strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ +contains:[{begin:/\\\n/}] +}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ +className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ +className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 +},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ +type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], +keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], +literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], +_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] +},b={className:"function.dispatch",relevance:0,keywords:{ +_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] +}, +begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) +},m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", +begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ +begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ +begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ +className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, +contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, +relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] +},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", +aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ +match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], +className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ +keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), +built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], +literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ +begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ +begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] +},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, +keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, +end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ +},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ +begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, +contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) +;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], +o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ +illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t] +},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ +begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], +keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, +contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ +begin:"\x3c!--|--\x3e"},{begin:""}]}] +}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", +end:"$",keywords:{ +keyword:"if else elif endif define undef warning error line region endregion pragma checksum" +}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, +illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" +},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", +relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", +begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ +className:"string",begin:/"/,end:/"/}]},{ +beginKeywords:"new return throw await else",relevance:0},{className:"function", +begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ +beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", +relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", +begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, +contains:[g,a,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ +const n=e.regex,t=ie(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ +name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ +keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, +contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ +},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 +},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 +},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ +begin:":("+oe.join("|")+")"},{begin:":(:)?("+le.join("|")+")"}] +},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b"},{ +begin:/:/,end:/[;}{]/, +contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ +begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" +},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, +excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", +relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ +},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ +$pattern:/[a-z-]+/,keyword:"and or not only",attribute:se.join(" ")},contains:[{ +begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ +className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}},grmr_diff:e=>{ +const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ +className:"meta",relevance:10, +match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) +},{className:"comment",variants:[{ +begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), +end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ +className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, +end:/$/}]}},grmr_go:e=>{const n={ +keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], +type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], +literal:["true","false","iota","nil"], +built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] +};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex;return{name:"GraphQL",aliases:["gql"], +case_insensitive:!0,disableAutodetect:!1,keywords:{ +keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], +literal:["true","false","null"]}, +contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ +scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", +begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, +end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ +scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), +relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ +className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ +begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, +end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ +begin:/\$\{(.*?)\}/}]},r={className:"literal", +begin:/\bon|off|true|false|yes|no\b/},s={className:"string", +contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ +begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] +},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 +},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ +name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, +contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ +begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), +className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ +const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+pe("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ +keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"], +literal:["false","true","null"], +type:["char","boolean","long","float","int","byte","short","double"], +built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ +begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} +;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, +relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ +begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, +className:"string",contains:[e.BACKSLASH_ESCAPE] +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ +match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ +1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ +begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", +3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", +3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"new throw return else",relevance:0},{ +begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ +2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0, +contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,me,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},me,r]}},grmr_javascript:Oe, +grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", +beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{ +className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ +match:/[{}[\],:]/,className:"punctuation",relevance:0 +},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], +illegal:"\\S"}},grmr_kotlin:e=>{const n={ +keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", +built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", +literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" +},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ +className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", +variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", +illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, +contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ +className:"meta", +begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" +},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, +end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] +},l=me,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ +variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, +contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], +{name:"Kotlin",aliases:["kt","kts"],keywords:n, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", +begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", +begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", +begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", +returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ +begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, +contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, +keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, +endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, +endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 +},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ +begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ +3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, +illegal:"extends implements",contains:[{ +beginKeywords:"public protected internal private constructor" +},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, +excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, +excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", +end:"$",illegal:"\n"},l]}},grmr_less:e=>{ +const n=ie(e),t=de,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ +className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, +relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", +attribute:se.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, +relevance:0} +;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ +begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", +excludeEnd:!0} +},n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ +className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 +},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ +begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, +contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", +returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ +},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b", +end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] +},m={className:"keyword", +begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", +starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ +className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a +}],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ +begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, +returnEnd:!0,illegal:"[<='$\"]",relevance:0, +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ +begin:"\\b("+re.join("|")+")\\b",className:"selector-tag" +},n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ +className:"selector-pseudo",begin:":("+oe.join("|")+")"},{ +className:"selector-pseudo",begin:":(:)?("+le.join("|")+")"},{begin:/\(/, +end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ +begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} +;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), +{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, +grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] +},i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 +})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, +literal:"true false nil", +keyword:"and break do else elseif end for goto if in local not or repeat return then until while", +built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" +},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", +contains:[e.inherit(e.TITLE_MODE,{ +begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", +begin:"\\(",endsWithParent:!0,contains:i}].concat(i) +},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", +begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ +className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ +const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ +variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ +begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, +relevance:2},{ +begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), +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}]},a={className:"strong",contains:[], +variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] +},i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ +begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] +}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) +;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) +})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ +className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ +begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", +contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", +end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, +end:"$"},{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}]},{ +begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ +className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ +className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{ +const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, +keyword:["@interface","@class","@protocol","@implementation"]};return{ +name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], +keywords:{"variable.language":["this","super"],$pattern:n, +keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], +literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], +built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], +type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] +},illegal:"/,end:/$/,illegal:"\\n" +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", +begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, +contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, +relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ +$pattern:/[\w.]+/, +keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" +},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, +end:/\}/},s={variants:[{begin:/\$\d/},{ +begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") +},{begin:/[$%@][^\s\w{]/,relevance:0}] +},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{ +const r="\\1"===i?i:n.concat(i,a) +;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) +},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ +endsWithParent:!0}),r,{className:"string",contains:o,variants:[{ +begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", +end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ +begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", +relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", +contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ +begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number", +begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", +relevance:0},{ +begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", +keywords:"split return print reverse grep",relevance:0, +contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ +begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{ +begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{ +className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ +begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0 +}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{ +begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub", +end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ +begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", +subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] +}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a, +contains:g}},grmr_php:e=>{ +const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ +scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ +begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null +}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ +illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ +begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, +contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ +n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ +begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ +begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ +begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ +begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" +}],relevance:0 +},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ +keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ +n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) +})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ +match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ +1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ +match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" +}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ +match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", +3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], +scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", +3:"variable.language"}}]},E={scope:"attr", +match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, +begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] +},N={relevance:0, +match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], +scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(N) +;const w=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, +keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, +endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ +begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, +contains:["self",...w]},...w,{scope:"meta",match:i}] +},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ +scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, +keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, +contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ +begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ +begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,N,f,{ +match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ +scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, +excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" +},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", +begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, +contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ +beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", +illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ +beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ +beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, +contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ +beginKeywords:"use",relevance:0,end:";",contains:[{ +match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} +},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ +begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", +end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 +},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, +skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, +contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", +aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ +const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ +$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, +built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], +literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], +type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] +},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, +end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ +className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, +end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, +relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ +begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, +end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, +contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ +className:"number",relevance:0,variants:[{ +begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ +begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ +begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` +},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` +}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, +contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ +className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, +end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, +contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ +name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, +illegal:/(<\/|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if", +relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{ +1:"keyword",3:"title.function"},contains:[m]},{variants:[{ +match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], +scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ +className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, +grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", +starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ +begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ +const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) +;return{name:"R",keywords:{$pattern:t, +keyword:"function if in break next repeat else for while", +literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", +built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" +},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, +starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), +endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ +scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 +}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] +}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], +variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', +relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ +1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, +match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ +2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, +match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ +match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", +contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ +const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ +"variable.constant":["__FILE__","__LINE__","__ENCODING__"], +"variable.language":["self","super"], +keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], +built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], +literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ +begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] +}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 +}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, +end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ +begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ +begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, +end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ +begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ +begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ +begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ +begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ +begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), +contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, +contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", +relevance:0,variants:[{ +begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ +begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" +},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ +begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ +begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ +className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, +keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ +match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", +4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ +2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ +1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ +match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ +begin:e.IDENT_RE+"::"},{className:"symbol", +begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", +begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", +begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ +className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, +relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", +keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], +illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ +begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", +end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) +;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} +},{className:"meta.prompt", +begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", +starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", +aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, +contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, +grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0, +begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,e.IDENT_RE,n.lookahead(/\s*\(/)) +},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] +;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, +keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], +literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}}, +grmr_scss:e=>{const n=ie(e),t=le,a=oe,i="@[a-z-]+",r={className:"variable", +begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", +case_insensitive:!0,illegal:"[=/|']", +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ +className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ +className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 +},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", +begin:"\\b("+re.join("|")+")\\b",relevance:0},{className:"selector-pseudo", +begin:":("+a.join("|")+")"},{className:"selector-pseudo", +begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, +contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", +begin:"\\b("+ce.join("|")+")\\b"},{ +begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" +},{begin:/:/,end:/[;}{]/,relevance:0, +contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] +},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ +begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, +keyword:"and or not only",attribute:se.join(" ")},contains:[{begin:i, +className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" +},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] +},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", +aliases:["console","shellsession"],contains:[{className:"meta.prompt", +begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, +subLanguage:"bash"}}]}),grmr_sql:e=>{ +const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ +begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} +;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ +$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t +;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) +})(l,{when:e=>e.length<3}),literal:a,type:i, +built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] +},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, +keyword:l.concat(s),literal:a,type:i}},{className:"type", +begin:n.either("double precision","large object","with timezone","without timezone") +},c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", +variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, +contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ +className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, +relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 +},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ +match:[/\./,m(...xe,...Me)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), +relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ +className:"keyword", +match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Se).map(ke),...Me)}]},l={ +$pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Re),literal:Ce},c=[i,r,o],g=[{ +match:b(/\./,m(...De)),relevance:0},{className:"built_in", +match:b(/\b/,m(...De),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ +className:"operator",relevance:0,variants:[{match:Be},{match:`\\.(\\.|${Le})+`}] +}],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, +variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ +match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ +},{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ +match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] +}),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) +}),N=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ +}),w=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),N(e)] +}),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),N(e)]}),O={ +className:"string", +variants:[w(),w("#"),w("##"),w("###"),v(),v("#"),v("##"),v("###")] +},k=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, +contains:[e.BACKSLASH_ESCAPE]}],x={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, +contains:k},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, +contains:[...k,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},S={ +scope:"regexp",variants:[M("###"),M("##"),M("#"),x]},A={match:b(/`/,Fe,/`/) +},C=[A,{className:"variable",match:/\$\d+/},{className:"variable", +match:`\\$${ze}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ +contains:[{begin:/\(/,end:/\)/,keywords:Pe,contains:[...p,f,O]}]}},{ +scope:"keyword",match:b(/@/,m(...je))},{scope:"meta",match:b(/@/,Fe)}],R={ +match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", +match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,ze,"+") +},{className:"type",match:Ue,relevance:0},{match:/[?!]+/,relevance:0},{ +match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(Ue)),relevance:0}]},D={ +begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) +;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ +match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 +},...a,S,...c,...g,...p,f,O,...C,...T,R]},L={begin://, +keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, +contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, +relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", +match:Fe}]},...a,...c,...p,f,O,...T,R,I],endsParent:!0,illegal:/["']/},$={ +match:[/(func|macro)/,/\s+/,m(A.match,Fe,Be)],className:{1:"keyword", +3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},z={ +match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, +contains:[L,B,n],illegal:/\[|%/},F={match:[/operator/,/\s+/,Be],className:{ +1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,Ue],className:{ +1:"keyword",3:"title"},contains:[R],keywords:[...Te,...Ce],end:/}/} +;for(const e of O.variants){const n=e.contains.find((e=>"interpol"===e.label)) +;n.keywords=l;const t=[...c,...g,...p,f,O,...C];n.contains=[...t,{begin:/\(/, +end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l, +contains:[...a,$,z,{beginKeywords:"struct protocol class extension enum actor", +end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{ +className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c] +},F,U,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0 +},S,...c,...g,...p,f,O,...C,...T,R,I]}},grmr_typescript:e=>{ +const n=Oe(e),t=_e,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ +beginKeywords:"namespace",end:/\{/,excludeEnd:!0, +contains:[n.exports.CLASS_REFERENCE]},r={beginKeywords:"interface",end:/\{/, +excludeEnd:!0,keywords:{keyword:"interface extends",built_in:a}, +contains:[n.exports.CLASS_REFERENCE]},s={$pattern:_e, +keyword:he.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), +literal:fe,built_in:ve.concat(a),"variable.language":we},o={className:"meta", +begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) +;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} +;return Object.assign(n.keywords,s), +n.exports.PARAMS_CONTAINS.push(o),n.contains=n.contains.concat([o,i,r]), +l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, +begin:/^\s*['"]use strict['"]/ +}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ +name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ +const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ +className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ +begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ +begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] +},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] +}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) +;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, +classNameAliases:{label:"symbol"},keywords:{ +keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", +built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", +type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", +literal:"true false nothing"}, +illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ +className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, +end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, +variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ +},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ +begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ +className:"label",begin:/^\w+:/},o,l,{className:"meta", +begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, +end:/$/,keywords:{ +keyword:"const disable else elseif enable end externalsource if region then"}, +contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) +;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, +keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] +},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], +className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ +match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ +begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", +3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, +className:"type"},{className:"keyword", +match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ +},{className:"number",relevance:0, +match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ +}]}},grmr_xml:e=>{ +const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ +className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, +contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] +},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ +className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ +endsWithParent:!0,illegal:/`]+/}]}]}]};return{ +name:"HTML, XML", +aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], +case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ +className:"meta",begin://,contains:[i,r,o,s]}]}] +},e.COMMENT(//,{relevance:10}),{begin://, +relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, +relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ +end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ +end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ +className:"tag",begin:/<>|<\/>/},{className:"tag", +begin:n.concat(//,/>/,/\s/)))), +end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ +className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ +className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} +},grmr_yaml:e=>{ +const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ +className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ +},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", +variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ +end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, +end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", +contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ +begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ +begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", +relevance:10},{className:"string", +begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ +begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, +relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", +begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t +},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", +begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", +relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ +className:"number", +begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" +},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] +;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, +aliases:["yml"],contains:l}}});const He=ae;for(const e of Object.keys(Ke)){ +const n=e.replace("grmr_","").replace("_","-");He.registerLanguage(n,Ke[e])} +return He}() +;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file diff --git a/resources/marked.min.js b/resources/marked.min.js new file mode 100644 index 0000000..b4e0d73 --- /dev/null +++ b/resources/marked.min.js @@ -0,0 +1,69 @@ +/** + * marked v15.0.12 - a markdown parser + * Copyright (c) 2011-2025, Christopher Jeffrey. (MIT Licensed) + * https://github.com/markedjs/marked + */ + +/** + * DO NOT EDIT THIS FILE + * The code in this file is generated from files in ./src/ + */ +(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("marked",f)}else {g["marked"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports}; +"use strict";var H=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var Te=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var ye=(l,e)=>{for(var t in e)H(l,t,{get:e[t],enumerable:!0})},Re=(l,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Te(e))!we.call(l,s)&&s!==t&&H(l,s,{get:()=>e[s],enumerable:!(n=be(e,s))||n.enumerable});return l};var Se=l=>Re(H({},"__esModule",{value:!0}),l);var kt={};ye(kt,{Hooks:()=>L,Lexer:()=>x,Marked:()=>E,Parser:()=>b,Renderer:()=>$,TextRenderer:()=>_,Tokenizer:()=>S,defaults:()=>w,getDefaults:()=>z,lexer:()=>ht,marked:()=>k,options:()=>it,parse:()=>pt,parseInline:()=>ct,parser:()=>ut,setOptions:()=>ot,use:()=>lt,walkTokens:()=>at});module.exports=Se(kt);function z(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var w=z();function N(l){w=l}var I={exec:()=>null};function h(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,i)=>{let r=typeof i=="string"?i:i.source;return r=r.replace(m.caret,"$1"),t=t.replace(s,r),n},getRegex:()=>new RegExp(t,e)};return n}var m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}#`),htmlBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}<(?:[a-z].*>|!--)`,"i")},$e=/^(?:[ \t]*(?:\n|$))+/,_e=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,Le=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,O=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ze=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,F=/(?:[*+-]|\d{1,9}[.)])/,ie=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,oe=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Me=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Q=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Pe=/^[^\n]+/,U=/(?!\s*\])(?:\\.|[^\[\]\\])+/,Ae=h(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",U).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Ee=h(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,F).getRegex(),v="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",K=/|$))/,Ce=h("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",K).replace("tag",v).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),le=h(Q).replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Ie=h(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",le).getRegex(),X={blockquote:Ie,code:_e,def:Ae,fences:Le,heading:ze,hr:O,html:Ce,lheading:oe,list:Ee,newline:$e,paragraph:le,table:I,text:Pe},re=h("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Oe={...X,lheading:Me,table:re,paragraph:h(Q).replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",re).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex()},Be={...X,html:h(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",K).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:I,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:h(Q).replace("hr",O).replace("heading",` *#{1,6} *[^ +]`).replace("lheading",oe).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},qe=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,ve=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,ae=/^( {2,}|\\)\n(?!\s*$)/,De=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\]*?>/g,ue=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,je=h(ue,"u").replace(/punct/g,D).getRegex(),Fe=h(ue,"u").replace(/punct/g,pe).getRegex(),he="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Qe=h(he,"gu").replace(/notPunctSpace/g,ce).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Ue=h(he,"gu").replace(/notPunctSpace/g,He).replace(/punctSpace/g,Ge).replace(/punct/g,pe).getRegex(),Ke=h("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ce).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Xe=h(/\\(punct)/,"gu").replace(/punct/g,D).getRegex(),We=h(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Je=h(K).replace("(?:-->|$)","-->").getRegex(),Ve=h("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",Je).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),q=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ye=h(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label",q).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ke=h(/^!?\[(label)\]\[(ref)\]/).replace("label",q).replace("ref",U).getRegex(),ge=h(/^!?\[(ref)\](?:\[\])?/).replace("ref",U).getRegex(),et=h("reflink|nolink(?!\\()","g").replace("reflink",ke).replace("nolink",ge).getRegex(),J={_backpedal:I,anyPunctuation:Xe,autolink:We,blockSkip:Ne,br:ae,code:ve,del:I,emStrongLDelim:je,emStrongRDelimAst:Qe,emStrongRDelimUnd:Ke,escape:qe,link:Ye,nolink:ge,punctuation:Ze,reflink:ke,reflinkSearch:et,tag:Ve,text:De,url:I},tt={...J,link:h(/^!?\[(label)\]\((.*?)\)/).replace("label",q).getRegex(),reflink:h(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",q).getRegex()},j={...J,emStrongRDelimAst:Ue,emStrongLDelim:Fe,url:h(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\":">",'"':""","'":"'"},fe=l=>st[l];function R(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,fe)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,fe);return l}function V(l){try{l=encodeURI(l).replace(m.percentDecode,"%")}catch{return null}return l}function Y(l,e){let t=l.replace(m.findPipe,(i,r,o)=>{let a=!1,c=r;for(;--c>=0&&o[c]==="\\";)a=!a;return a?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length0?-2:-1}function me(l,e,t,n,s){let i=e.href,r=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=!0;let a={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:i,title:r,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,a}function rt(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(` +`).map(i=>{let r=i.match(t.other.beginningSpace);if(r===null)return i;let[o]=r;return o.length>=s.length?i.slice(s.length):i}).join(` +`)}var S=class{options;rules;lexer;constructor(e){this.options=e||w}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=t[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?n:A(n,` +`)}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=rt(n,t[3]||"",this.rules);return{type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=A(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:A(t[0],` +`)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=A(t[0],` +`).split(` +`),s="",i="",r=[];for(;n.length>0;){let o=!1,a=[],c;for(c=0;c1,i={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let r=this.rules.other.listItemRegex(n),o=!1;for(;e;){let c=!1,p="",u="";if(!(t=r.exec(e))||this.rules.block.hr.test(e))break;p=t[0],e=e.substring(p.length);let d=t[2].split(` +`,1)[0].replace(this.rules.other.listReplaceTabs,Z=>" ".repeat(3*Z.length)),g=e.split(` +`,1)[0],T=!d.trim(),f=0;if(this.options.pedantic?(f=2,u=d.trimStart()):T?f=t[1].length+1:(f=t[2].search(this.rules.other.nonSpaceChar),f=f>4?1:f,u=d.slice(f),f+=t[1].length),T&&this.rules.other.blankLine.test(g)&&(p+=g+` +`,e=e.substring(g.length+1),c=!0),!c){let Z=this.rules.other.nextBulletRegex(f),te=this.rules.other.hrRegex(f),ne=this.rules.other.fencesBeginRegex(f),se=this.rules.other.headingBeginRegex(f),xe=this.rules.other.htmlBeginRegex(f);for(;e;){let G=e.split(` +`,1)[0],C;if(g=G,this.options.pedantic?(g=g.replace(this.rules.other.listReplaceNesting," "),C=g):C=g.replace(this.rules.other.tabCharGlobal," "),ne.test(g)||se.test(g)||xe.test(g)||Z.test(g)||te.test(g))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!g.trim())u+=` +`+C.slice(f);else{if(T||d.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||ne.test(d)||se.test(d)||te.test(d))break;u+=` +`+g}!T&&!g.trim()&&(T=!0),p+=G+` +`,e=e.substring(G.length+1),d=C.slice(f)}}i.loose||(o?i.loose=!0:this.rules.other.doubleBlankLine.test(p)&&(o=!0));let y=null,ee;this.options.gfm&&(y=this.rules.other.listIsTask.exec(u),y&&(ee=y[0]!=="[ ] ",u=u.replace(this.rules.other.listReplaceTask,""))),i.items.push({type:"list_item",raw:p,task:!!y,checked:ee,loose:!1,text:u,tokens:[]}),i.raw+=p}let a=i.items.at(-1);if(a)a.raw=a.raw.trimEnd(),a.text=a.text.trimEnd();else return;i.raw=i.raw.trimEnd();for(let c=0;cd.type==="space"),u=p.length>0&&p.some(d=>this.rules.other.anyLine.test(d.raw));i.loose=u}if(i.loose)for(let c=0;c({text:a,tokens:this.lexer.inline(a),header:!1,align:r.align[c]})));return r}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:t[2].charAt(0)==="="?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===` +`?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let r=A(n.slice(0,-1),"\\");if((n.length-r.length)%2===0)return}else{let r=de(t[2],"()");if(r===-2)return;if(r>-1){let a=(t[0].indexOf("!")===0?5:4)+t[1].length+r;t[2]=t[2].substring(0,r),t[0]=t[0].substring(0,a).trim(),t[3]=""}}let s=t[2],i="";if(this.options.pedantic){let r=this.rules.other.pedanticHrefTitle.exec(s);r&&(s=r[1],i=r[3])}else i=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),me(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:i&&i.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),i=t[s.toLowerCase()];if(!i){let r=n[0].charAt(0);return{type:"text",raw:r,text:r}}return me(n,i,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||s[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){let r=[...s[0]].length-1,o,a,c=r,p=0,u=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(u.lastIndex=0,t=t.slice(-1*e.length+r);(s=u.exec(t))!=null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(a=[...o].length,s[3]||s[4]){c+=a;continue}else if((s[5]||s[6])&&r%3&&!((r+a)%3)){p+=a;continue}if(c-=a,c>0)continue;a=Math.min(a,a+c+p);let d=[...s[0]][0].length,g=e.slice(0,r+s.index+d+a);if(Math.min(r,a)%2){let f=g.slice(1,-1);return{type:"em",raw:g,text:f,tokens:this.lexer.inlineTokens(f)}}let T=g.slice(2,-2);return{type:"strong",raw:g,text:T,tokens:this.lexer.inlineTokens(T)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),i=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&i&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){let t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else{let i;do i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(i!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0]}return{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;tokenizer;inlineQueue;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||w,this.options.tokenizer=this.options.tokenizer||new S,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let t={other:m,block:B.normal,inline:P.normal};this.options.pedantic?(t.block=B.pedantic,t.inline=P.pedantic):this.options.gfm&&(t.block=B.gfm,this.options.breaks?t.inline=P.breaks:t.inline=P.gfm),this.tokenizer.rules=t}static get rules(){return{block:B,inline:P}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,` +`),this.blockTokens(e,this.tokens);for(let t=0;t(s=r.call({lexer:this},e,t))?(e=e.substring(s.raw.length),t.push(s),!0):!1))continue;if(s=this.tokenizer.space(e)){e=e.substring(s.raw.length);let r=t.at(-1);s.raw.length===1&&r!==void 0?r.raw+=` +`:t.push(s);continue}if(s=this.tokenizer.code(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="paragraph"||r?.type==="text"?(r.raw+=` +`+s.raw,r.text+=` +`+s.text,this.inlineQueue.at(-1).src=r.text):t.push(s);continue}if(s=this.tokenizer.fences(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.heading(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.hr(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.blockquote(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.list(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.html(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.def(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="paragraph"||r?.type==="text"?(r.raw+=` +`+s.raw,r.text+=` +`+s.raw,this.inlineQueue.at(-1).src=r.text):this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title});continue}if(s=this.tokenizer.table(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.lheading(e)){e=e.substring(s.raw.length),t.push(s);continue}let i=e;if(this.options.extensions?.startBlock){let r=1/0,o=e.slice(1),a;this.options.extensions.startBlock.forEach(c=>{a=c.call({lexer:this},o),typeof a=="number"&&a>=0&&(r=Math.min(r,a))}),r<1/0&&r>=0&&(i=e.substring(0,r+1))}if(this.state.top&&(s=this.tokenizer.paragraph(i))){let r=t.at(-1);n&&r?.type==="paragraph"?(r.raw+=` +`+s.raw,r.text+=` +`+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=r.text):t.push(s),n=i.length!==e.length,e=e.substring(s.raw.length);continue}if(s=this.tokenizer.text(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="text"?(r.raw+=` +`+s.raw,r.text+=` +`+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=r.text):t.push(s);continue}if(e){let r="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(r);break}else throw new Error(r)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,s=null;if(this.tokens.links){let o=Object.keys(this.tokens.links);if(o.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!=null;)o.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!=null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!=null;)n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);let i=!1,r="";for(;e;){i||(r=""),i=!1;let o;if(this.options.extensions?.inline?.some(c=>(o=c.call({lexer:this},e,t))?(e=e.substring(o.raw.length),t.push(o),!0):!1))continue;if(o=this.tokenizer.escape(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.tag(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.link(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(o.raw.length);let c=t.at(-1);o.type==="text"&&c?.type==="text"?(c.raw+=o.raw,c.text+=o.text):t.push(o);continue}if(o=this.tokenizer.emStrong(e,n,r)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.codespan(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.br(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.del(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.autolink(e)){e=e.substring(o.raw.length),t.push(o);continue}if(!this.state.inLink&&(o=this.tokenizer.url(e))){e=e.substring(o.raw.length),t.push(o);continue}let a=e;if(this.options.extensions?.startInline){let c=1/0,p=e.slice(1),u;this.options.extensions.startInline.forEach(d=>{u=d.call({lexer:this},p),typeof u=="number"&&u>=0&&(c=Math.min(c,u))}),c<1/0&&c>=0&&(a=e.substring(0,c+1))}if(o=this.tokenizer.inlineText(a)){e=e.substring(o.raw.length),o.raw.slice(-1)!=="_"&&(r=o.raw.slice(-1)),i=!0;let c=t.at(-1);c?.type==="text"?(c.raw+=o.raw,c.text+=o.text):t.push(o);continue}if(e){let c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}else throw new Error(c)}}return t}};var $=class{options;parser;constructor(e){this.options=e||w}space(e){return""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],i=e.replace(m.endingNewline,"")+` +`;return s?'
'+(n?i:R(i,!0))+`
+`:"
"+(n?i:R(i,!0))+`
+`}blockquote({tokens:e}){return`
+${this.parser.parse(e)}
+`}html({text:e}){return e}heading({tokens:e,depth:t}){return`${this.parser.parseInline(e)} +`}hr(e){return`
+`}list(e){let t=e.ordered,n=e.start,s="";for(let o=0;o +`+s+" +`}listitem(e){let t="";if(e.task){let n=this.checkbox({checked:!!e.checked});e.loose?e.tokens[0]?.type==="paragraph"?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&e.tokens[0].tokens[0].type==="text"&&(e.tokens[0].tokens[0].text=n+" "+R(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=!0)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:!0}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`
  • ${t}
  • +`}checkbox({checked:e}){return"'}paragraph({tokens:e}){return`

    ${this.parser.parseInline(e)}

    +`}table(e){let t="",n="";for(let i=0;i${s}`),` + +`+t+` +`+s+`
    +`}tablerow({text:e}){return` +${e} +`}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+` +`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${R(e,!0)}`}br(e){return"
    "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),i=V(e);if(i===null)return s;e=i;let r='
    ",r}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let i=V(e);if(i===null)return R(n);e=i;let r=`${n}{let o=i[r].flat(1/0);n=n.concat(this.walkTokens(o,t))}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)))}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let r=t.renderers[i.name];r?t.renderers[i.name]=function(...o){let a=i.renderer.apply(this,o);return a===!1&&(a=r.apply(this,o)),a}:t.renderers[i.name]=i.renderer}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let r=t[i.level];r?r.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]))}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens)}),s.extensions=t),n.renderer){let i=this.defaults.renderer||new $(this.defaults);for(let r in n.renderer){if(!(r in i))throw new Error(`renderer '${r}' does not exist`);if(["options","parser"].includes(r))continue;let o=r,a=n.renderer[o],c=i[o];i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u||""}}s.renderer=i}if(n.tokenizer){let i=this.defaults.tokenizer||new S(this.defaults);for(let r in n.tokenizer){if(!(r in i))throw new Error(`tokenizer '${r}' does not exist`);if(["options","rules","lexer"].includes(r))continue;let o=r,a=n.tokenizer[o],c=i[o];i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u}}s.tokenizer=i}if(n.hooks){let i=this.defaults.hooks||new L;for(let r in n.hooks){if(!(r in i))throw new Error(`hook '${r}' does not exist`);if(["options","block"].includes(r))continue;let o=r,a=n.hooks[o],c=i[o];L.passThroughHooks.has(r)?i[o]=p=>{if(this.defaults.async)return Promise.resolve(a.call(i,p)).then(d=>c.call(i,d));let u=a.call(i,p);return c.call(i,u)}:i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u}}s.hooks=i}if(n.walkTokens){let i=this.defaults.walkTokens,r=n.walkTokens;s.walkTokens=function(o){let a=[];return a.push(r.call(this,o)),i&&(a=a.concat(i.call(this,o))),a}}this.defaults={...this.defaults,...s}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return(n,s)=>{let i={...s},r={...this.defaults,...i},o=this.onError(!!r.silent,!!r.async);if(this.defaults.async===!0&&i.async===!1)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);let a=r.hooks?r.hooks.provideLexer():e?x.lex:x.lexInline,c=r.hooks?r.hooks.provideParser():e?b.parse:b.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(n):n).then(p=>a(p,r)).then(p=>r.hooks?r.hooks.processAllTokens(p):p).then(p=>r.walkTokens?Promise.all(this.walkTokens(p,r.walkTokens)).then(()=>p):p).then(p=>c(p,r)).then(p=>r.hooks?r.hooks.postprocess(p):p).catch(o);try{r.hooks&&(n=r.hooks.preprocess(n));let p=a(n,r);r.hooks&&(p=r.hooks.processAllTokens(p)),r.walkTokens&&this.walkTokens(p,r.walkTokens);let u=c(p,r);return r.hooks&&(u=r.hooks.postprocess(u)),u}catch(p){return o(p)}}}onError(e,t){return n=>{if(n.message+=` +Please report this to https://github.com/markedjs/marked.`,e){let s="

    An error occurred:

    "+R(n.message+"",!0)+"
    ";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var M=new E;function k(l,e){return M.parse(l,e)}k.options=k.setOptions=function(l){return M.setOptions(l),k.defaults=M.defaults,N(k.defaults),k};k.getDefaults=z;k.defaults=w;k.use=function(...l){return M.use(...l),k.defaults=M.defaults,N(k.defaults),k};k.walkTokens=function(l,e){return M.walkTokens(l,e)};k.parseInline=M.parseInline;k.Parser=b;k.parser=b.parse;k.Renderer=$;k.TextRenderer=_;k.Lexer=x;k.lexer=x.lex;k.Tokenizer=S;k.Hooks=L;k.parse=k;var it=k.options,ot=k.setOptions,lt=k.use,at=k.walkTokens,ct=k.parseInline,pt=k,ut=b.parse,ht=x.lex; + +if(__exports != exports)module.exports = exports;return module.exports})); diff --git a/src/commands/aiAssist.ts b/src/commands/aiAssist.ts index c0a0bb8..af2433d 100644 --- a/src/commands/aiAssist.ts +++ b/src/commands/aiAssist.ts @@ -1,8 +1,8 @@ import * as vscode from 'vscode'; -import * as https from 'https'; import { ErrorHandlers, StringUtils } from './helper'; import { ConnectionManager } from '../services/ConnectionManager'; import { PostgresMetadata } from '../common/types'; +import { AiService } from '../providers/chat/AiService'; // Interface for table schema information interface TableSchemaInfo { @@ -75,7 +75,9 @@ export async function cmdAiAssist(cell: vscode.NotebookCell | undefined, context try { const config = vscode.workspace.getConfiguration('postgresExplorer'); const provider = config.get('aiProvider') || 'vscode-lm'; - const modelInfo = await getModelInfo(provider, config); + + const aiService = new AiService(); + const modelInfo = await aiService.getModelInfo(provider, config); await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, @@ -90,12 +92,16 @@ export async function cmdAiAssist(cell: vscode.NotebookCell | undefined, context progress.report({ message: "Generating response..." }); + // Build the comprehensive prompt to be used as System Prompt + const systemPrompt = buildPrompt(userInput, cellContext); + const userTrigger = "Please provide the SQL query based on the instructions above."; + let responseText = ''; if (provider === 'vscode-lm') { - responseText = await callVsCodeLm(userInput, cellContext, token, config); + responseText = await aiService.callVsCodeLm(userTrigger, config, systemPrompt); } else { - responseText = await callDirectApi(provider, userInput, cellContext, config, outputChannel); + responseText = await aiService.callDirectApi(provider, userTrigger, config, systemPrompt); } // Parse the response to check for placement instruction @@ -479,181 +485,6 @@ async function fetchTableSchema(client: any, tableRef: { schema: string; table: }; } -async function getModelInfo(provider: string, config: vscode.WorkspaceConfiguration): Promise { - try { - const configuredModel = config.get('aiModel'); - - if (provider === 'vscode-lm') { - if (configuredModel) { - const baseName = configuredModel.replace(/\s*\(.*\)$/, '').trim(); - const allModels = await vscode.lm.selectChatModels({}); - const matchingModels = allModels.filter(m => - m.id === baseName || m.name === baseName || m.family === baseName || - m.id === configuredModel || m.name === configuredModel || m.family === configuredModel - ); - if (matchingModels.length > 0) { - return matchingModels[0].name || matchingModels[0].id; - } - } - const models = await vscode.lm.selectChatModels({ family: 'gpt-4o' }); - if (models.length > 0) { - return models[0].name || models[0].id; - } - const anyModels = await vscode.lm.selectChatModels({}); - return anyModels.length > 0 ? (anyModels[0].name || anyModels[0].id) : 'Unknown'; - } else { - if (configuredModel) return configuredModel; - switch (provider) { - case 'openai': return 'gpt-4'; - case 'anthropic': return 'claude-3-5-sonnet-20241022'; - case 'gemini': return 'gemini-pro'; - case 'custom': return 'custom-model'; - default: return 'Unknown'; - } - } - } catch { - return 'Unknown'; - } -} - -async function callVsCodeLm(userInput: string, cellContext: CellContext, token: vscode.CancellationToken, config: vscode.WorkspaceConfiguration): Promise { - const configuredModel = config.get('aiModel'); - let models: vscode.LanguageModelChat[]; - - if (configuredModel) { - // Extract base name if format is "name (family)" - const baseName = configuredModel.replace(/\s*\(.*\)$/, '').trim(); - - // Try to find the specific model by name/id/family - const allModels = await vscode.lm.selectChatModels({}); - const matchingModels = allModels.filter(m => - m.id === baseName || - m.name === baseName || - m.family === baseName || - m.id === configuredModel || - m.name === configuredModel || - m.family === configuredModel - ); - models = matchingModels.length > 0 ? matchingModels : allModels; - } else { - // Default: prefer GPT-4 class models - models = await vscode.lm.selectChatModels({ family: 'gpt-4o' }); - if (models.length === 0) { - models = await vscode.lm.selectChatModels({}); - } - } - - const model = models[0]; - if (!model) { - throw new Error('No AI models available via VS Code API. Please ensure GitHub Copilot Chat is installed or switch provider.'); - } - - const messages = [ - vscode.LanguageModelChatMessage.User(buildPrompt(userInput, cellContext)) - ]; - - const chatRequest = await model.sendRequest(messages, {}, token); - let responseText = ''; - - for await (const fragment of chatRequest.text) { - responseText += fragment; - } - return responseText; -} - -async function callDirectApi(provider: string, userInput: string, cellContext: CellContext, config: vscode.WorkspaceConfiguration, outputChannel: vscode.OutputChannel): Promise { - const apiKey = config.get('aiApiKey'); - if (!apiKey) { - throw new Error(`API Key is required for ${provider} provider. Please configure postgresExplorer.aiApiKey.`); - } - - let endpoint = ''; - let model = config.get('aiModel'); - let headers: any = { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${apiKey}` - }; - let body: any = {}; - const prompt = buildPrompt(userInput, cellContext); - - if (provider === 'openai') { - endpoint = 'https://api.openai.com/v1/chat/completions'; - model = model || 'gpt-4'; - body = { - model: model, - messages: [{ role: 'user', content: prompt }], - temperature: 0.1 - }; - } else if (provider === 'anthropic') { - endpoint = 'https://api.anthropic.com/v1/messages'; - model = model || 'claude-3-5-sonnet-20241022'; - headers['x-api-key'] = apiKey; - headers['anthropic-version'] = '2023-06-01'; - delete headers['Authorization']; // Anthropic uses x-api-key - body = { - model: model, - messages: [{ role: 'user', content: prompt }], - max_tokens: 4096 - }; - } else if (provider === 'gemini') { - model = model || 'gemini-pro'; - endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`; - outputChannel.appendLine(`Using Gemini endpoint: ${endpoint}`); - headers['X-goog-api-key'] = apiKey; - delete headers['Authorization']; - body = { - contents: [{ - parts: [{ text: prompt }] - }] - }; - } else if (provider === 'custom') { - endpoint = config.get('aiEndpoint') || ''; - if (!endpoint) throw new Error('Endpoint is required for custom provider'); - model = model || 'gpt-3.5-turbo'; // Default fallback - body = { - model: model, - messages: [{ role: 'user', content: prompt }] - }; - } - - return new Promise((resolve, reject) => { - const url = new URL(endpoint); - const options = { - hostname: url.hostname, - path: url.pathname + url.search, - method: 'POST', - headers: headers - }; - - const req = https.request(options, (res) => { - let data = ''; - res.on('data', (chunk) => data += chunk); - res.on('end', () => { - if (res.statusCode && res.statusCode >= 400) { - reject(new Error(`API Request failed with status ${res.statusCode}: ${data}`)); - return; - } - try { - const json = JSON.parse(data); - if (provider === 'anthropic') { - resolve(json.content[0].text); - } else if (provider === 'gemini') { - resolve(json.candidates[0].content.parts[0].text); - } else { - resolve(json.choices[0].message.content); - } - } catch (e) { - reject(new Error('Failed to parse API response')); - } - }); - }); - - req.on('error', (e) => reject(e)); - req.write(JSON.stringify(body)); - req.end(); - }); -} - function buildPrompt(userInput: string, cellContext: CellContext): string { const { currentQuery, previousCells, lastOutput, tableSchemas, databaseInfo } = cellContext; @@ -798,248 +629,48 @@ const AiTaskSelector = { { label: '$(add) Add WHERE Clause', description: 'Add filtering conditions', detail: 'Prompts for conditions to filter results' }, { label: '$(filter) Add Pagination', description: 'Add LIMIT and OFFSET', detail: 'Adds pagination with sensible defaults' }, { label: '$(sort-precedence) Add ORDER BY', description: 'Add sorting to results', detail: 'Adds ORDER BY clause with appropriate columns' }, - { label: '$(group-by-ref-type) Add GROUP BY', description: 'Add aggregation', detail: 'Transforms query to use GROUP BY with aggregates' }, - - // Query Transformation - { label: '$(file-submodule) Convert to CTE', description: 'Refactor using WITH clause', detail: 'Extracts subqueries into Common Table Expressions' }, - { label: '$(symbol-interface) Convert to Subquery', description: 'Use subqueries instead of JOINs', detail: 'Transforms JOINs to correlated or uncorrelated subqueries' }, - { label: '$(references) Add JOINs', description: 'Join with related tables', detail: 'Adds appropriate JOINs based on foreign keys' }, - - // Security & Safety - { label: '$(shield) Add Safety Checks', description: 'Add guards against common issues', detail: 'Adds NULL checks, type casting, and boundary conditions' }, - { label: '$(lock) Parameterize Query', description: 'Convert to prepared statement', detail: 'Replaces literals with $1, $2 placeholders' }, - - // Data Operations - { label: '$(diff-insert) Generate INSERT', description: 'Create INSERT from SELECT', detail: 'Wraps SELECT as INSERT INTO ... SELECT' }, - { label: '$(diff-modified) Generate UPDATE', description: 'Create UPDATE statement', detail: 'Generates UPDATE with proper WHERE clause' }, - { label: '$(diff-removed) Generate DELETE', description: 'Create safe DELETE statement', detail: 'Generates DELETE with confirmation checks' }, - - // Advanced - { label: '$(beaker) Add Window Functions', description: 'Use window functions', detail: 'Adds ROW_NUMBER, RANK, LAG, LEAD, etc.' }, - { label: '$(combine) Create UNION Query', description: 'Combine with another query', detail: 'Structures query for UNION/INTERSECT/EXCEPT' }, - { label: '$(json) Handle JSON', description: 'Add JSON operators', detail: 'Uses ->, ->>, jsonb_* functions appropriately' } - ], + { label: '$(group-by-ref-type) Add GROUP BY', description: 'Aggregate results', detail: 'Adds GROUP BY and aggregation functions' }, - /** - * Task instruction templates with detailed prompts - */ - instructions: { - 'Custom Instruction': null, // Will prompt user - - 'Explain Query': `Add comprehensive inline comments to this SQL query explaining: -- The overall purpose of the query -- What each SELECT column represents -- The reason for each JOIN and its relationship -- What each WHERE condition filters -- The purpose of GROUP BY, ORDER BY, and any other clauses -- Any complex expressions or subqueries -Keep the query functional while making it self-documenting.`, - - 'What Does This Do?': `Add a detailed block comment at the top of the query that explains: -- What this query does in plain English -- What tables it reads from and why -- What the expected output represents -- Any important assumptions or limitations -Do not modify the query logic itself.`, - - 'Fix Syntax Errors': `Fix any syntax errors in this SQL query including: -- Missing or extra commas, parentheses, quotes -- Incorrect keyword spelling or ordering -- Missing semicolons or statement terminators -- Incorrect string escaping -- Invalid identifier quoting -Ensure the query is valid PostgreSQL syntax.`, - - 'Fix Logic Issues': `Identify and fix logical issues in this query: -- Incorrect JOIN conditions that could cause cartesian products -- WHERE conditions that might exclude intended rows -- NULL handling issues (use COALESCE, IS NULL, etc.) -- Incorrect aggregate function usage -- Off-by-one errors in date/number comparisons -Add comments explaining what was fixed and why.`, - - 'Debug Query': `Modify this query to help with debugging: -- Add EXPLAIN ANALYZE at the start (commented out for easy toggle) -- Add intermediate CTEs to break down complex logic -- Add comments showing expected row counts at each step -- Include RAISE NOTICE statements if this is a function -- Add diagnostic SELECT statements that can be uncommented`, - - 'Optimize Performance': `Optimize this query for better performance: -- Rewrite to use existing indexes effectively (check the schema info) -- Eliminate redundant subqueries or JOINs -- Use appropriate join types (consider LATERAL, EXISTS vs IN) -- Add query hints or settings if beneficial -- Consider materialized CTEs for repeated subqueries -- Optimize predicate pushdown -Add comments explaining the optimization rationale.`, - - 'Add EXPLAIN ANALYZE': `Wrap this query with EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) to analyze its execution plan. Add a comment header explaining how to interpret the results.`, - - 'Suggest Indexes': `Analyze this query and add comments suggesting: -- CREATE INDEX statements that would improve performance -- Which columns should be indexed and why -- Whether composite indexes would help -- Index type recommendations (B-tree, GIN, GiST, etc.) -Keep the original query unchanged, only add comments.`, - - 'Format Query': `Format this SQL query with proper styling: -- Consistent indentation (2 or 4 spaces) -- Each clause (SELECT, FROM, WHERE, etc.) on its own line -- Align similar elements vertically where it improves readability -- Logical grouping of related columns and conditions -- Appropriate line breaks for long expressions -Use uppercase for SQL keywords.`, - - 'Uppercase Keywords': `Convert all SQL keywords to uppercase while preserving: -- Original case for identifiers (table names, column names) -- Original case for string literals -- Original formatting and whitespace -Keywords include: SELECT, FROM, WHERE, JOIN, AND, OR, ON, AS, etc.`, - - 'Add Aliases': `Add meaningful table aliases to this query: -- Use short but descriptive aliases (e.g., 'u' for users, 'o' for orders) -- Apply aliases consistently throughout the query -- Add column aliases for computed/derived columns -- Use AS keyword explicitly for clarity`, - - 'Add WHERE Clause': `Add appropriate WHERE clause filtering based on: -- The table schemas and likely filter candidates -- Common filtering patterns for this type of query -- Add placeholder comments where user should specify values -Use parameterized placeholders ($1, $2) for values.`, - - 'Add Pagination': `Add pagination to this query: -- Add LIMIT and OFFSET clauses -- Use reasonable defaults (LIMIT 50, OFFSET 0) -- Add comments explaining how to adjust for different pages -- Consider adding a total count CTE if useful -- Ensure ORDER BY is present for consistent pagination`, - - 'Add ORDER BY': `Add an ORDER BY clause to this query: -- Choose appropriate columns based on the query context -- Use ASC/DESC based on likely user expectations -- Consider adding secondary sort columns for stability -- Add NULLS FIRST/LAST if NULL handling matters`, - - 'Add GROUP BY': `Transform this query to use GROUP BY: -- Identify appropriate grouping columns -- Add aggregate functions (COUNT, SUM, AVG, etc.) for other columns -- Include HAVING clause if filtering on aggregates is useful -- Consider adding grouping sets or rollup if appropriate`, - - 'Convert to CTE': `Refactor this query to use Common Table Expressions (WITH clause): -- Extract subqueries into named CTEs -- Break complex logic into readable steps -- Name CTEs descriptively -- Consider using RECURSIVE if applicable -- Maintain query correctness and performance`, - - 'Convert to Subquery': `Rewrite this query using subqueries instead of JOINs where appropriate: -- Use correlated subqueries for existence checks -- Use scalar subqueries for single-value lookups -- Use derived tables where performance is better -Add comments explaining the tradeoffs.`, - - 'Add JOINs': `Enhance this query by adding JOINs to related tables: -- Use the foreign key relationships from the schema -- Choose appropriate JOIN types (INNER, LEFT, etc.) -- Add useful columns from joined tables -- Ensure join conditions are correct`, - - 'Add Safety Checks': `Add safety checks to this query: -- COALESCE for potentially NULL values -- Type casting to prevent type errors -- Bounds checking for numeric operations -- Empty string handling -- Date/timestamp validation -Add comments explaining each safety measure.`, - - 'Parameterize Query': `Convert this query to use parameterized placeholders: -- Replace string literals with $1, $2, etc. -- Replace numeric literals that are likely user inputs -- Add a comment header listing parameters and their types -- Keep constant values as literals -Example: WHERE id = $1 AND status = $2`, - - 'Generate INSERT': `Transform this SELECT query into an INSERT statement: -- Create INSERT INTO table_name (columns) SELECT ... -- Match column order correctly -- Add RETURNING clause if useful -- Consider ON CONFLICT handling -Add comments about the target table.`, - - 'Generate UPDATE': `Generate an UPDATE statement based on this query: -- Create proper SET clauses -- Use appropriate WHERE conditions from the query -- Consider using FROM clause for complex updates -- Add RETURNING clause to see affected rows -Include safety comments about running updates.`, - - 'Generate DELETE': `Generate a safe DELETE statement: -- Create proper WHERE clause to limit deletion -- Add a comment with SELECT to preview rows first -- Consider using RETURNING to see deleted rows -- Add transaction wrapper comments (BEGIN/ROLLBACK/COMMIT) -IMPORTANT: Include safety warnings.`, - - 'Add Window Functions': `Enhance this query with window functions: -- Add ROW_NUMBER(), RANK(), or DENSE_RANK() for ordering -- Add LAG/LEAD for comparing with adjacent rows -- Add running totals with SUM() OVER -- Add moving averages if appropriate -- Use PARTITION BY for grouping within windows`, - - 'Create UNION Query': `Structure this query for combining with other results: -- Format for UNION/UNION ALL -- Ensure column compatibility -- Add type casts if needed -- Add placeholder for the second query -- Include comments about UNION vs UNION ALL choice`, - - 'Handle JSON': `Enhance this query with JSON/JSONB operations: -- Use appropriate operators (-> for object, ->> for text) -- Add jsonb_agg or json_agg for aggregation -- Use jsonb_build_object for constructing JSON -- Handle nested JSON access properly -- Add proper type casting from JSON values` - }, + // Advanced Operations + { label: '$(table) Convert to CTE', description: 'Refactor using Common Table Expressions', detail: 'Rewrites subqueries as WITH clauses for readability' }, + { label: '$(refresh) Convert to View', description: 'Create VIEW from query', detail: 'Wraps query in CREATE OR REPLACE VIEW' }, + { label: '$(symbol-function) Convert to Function', description: 'Create Function from query', detail: 'Wraps query in CREATE OR REPLACE FUNCTION' } + ], /** - * Select and get instruction for AI task + * Show task selector and return the user's choice/instruction */ async selectTask(): Promise { const selection = await vscode.window.showQuickPick(this.tasks, { - placeHolder: 'Select an AI task for your SQL query', - ignoreFocusOut: true, + placeHolder: 'Select an AI task or enter custom instruction', matchOnDescription: true, - matchOnDetail: true + matchOnDetail: true, + ignoreFocusOut: true }); if (!selection) { return undefined; } - // Find matching instruction key by extracting label text (remove icon) - const labelText = selection.label.replace(/^\$\([^)]+\)\s*/, ''); - const key = Object.keys(this.instructions).find(k => labelText === k); - - if (!key) { - return undefined; + if (selection.label.includes('Custom Instruction')) { + return await vscode.window.showInputBox({ + placeHolder: 'e.g., "Rewrite this query to filter by user status"', + prompt: 'Enter your specific instruction for the AI', + ignoreFocusOut: true + }); } - const instruction = this.instructions[key as keyof typeof AiTaskSelector.instructions]; - - // If custom instruction, prompt user - if (instruction === null) { - const input = await vscode.window.showInputBox({ - placeHolder: 'Describe how you want to modify this query...', - prompt: 'Enter detailed instructions for the AI (e.g., "Add a join with the orders table and filter by date range")', + // For specific tasks that might need extra input + if (selection.label.includes('Add WHERE Clause')) { + const condition = await vscode.window.showInputBox({ + placeHolder: 'e.g., status = \'active\' AND created_at > NOW() - INTERVAL \'1 day\'', + prompt: 'Enter the filtering condition', ignoreFocusOut: true }); - return input; + if (!condition) return undefined; + return `Add WHERE clause: ${condition}`; } - return instruction; + return selection.label.replace(/\$\([a-z-]+\)\s/, ''); // Return clean label as instruction } }; diff --git a/src/commands/helper.ts b/src/commands/helper.ts index 2df1e47..28b34f7 100644 --- a/src/commands/helper.ts +++ b/src/commands/helper.ts @@ -3,6 +3,9 @@ import { DatabaseTreeItem } from '../providers/DatabaseTreeProvider'; import { createAndShowNotebook, createMetadata, getConnectionWithPassword, validateItem, validateCategoryItem, validateRoleItem } from './connection'; import { ConnectionManager } from '../services/ConnectionManager'; +// Re-export SQL templates from sql/helper.ts for backward compatibility +export { SQL_TEMPLATES, QueryBuilder, MaintenanceTemplates } from './sql/helper'; + export { validateItem, validateCategoryItem, validateRoleItem }; /** @@ -46,48 +49,6 @@ export class NotebookBuilder { } } -/** - * Common SQL query templates - */ -export const SQL_TEMPLATES = { - DROP: { - TABLE: (schema: string, name: string) => - `-- Drop table\nDROP TABLE IF EXISTS "${schema}"."${name}";`, - VIEW: (schema: string, name: string) => - `-- Drop view\nDROP VIEW IF EXISTS ${schema}.${name};`, - MATERIALIZED_VIEW: (schema: string, name: string) => - `-- Drop materialized view\nDROP MATERIALIZED VIEW IF EXISTS ${schema}.${name};`, - FUNCTION: (schema: string, name: string, args: string) => - `-- Drop function\nDROP FUNCTION IF EXISTS ${schema}.${name}(${args});`, - INDEX: (schema: string, name: string) => - `-- Drop index\nDROP INDEX "${schema}"."${name}";`, - CONSTRAINT: (schema: string, table: string, name: string) => - `-- Drop constraint\nALTER TABLE "${schema}"."${table}"\nDROP CONSTRAINT "${name}";`, - TYPE: (schema: string, name: string) => - `-- Drop type\nDROP TYPE IF EXISTS ${schema}.${name} CASCADE;`, - EXTENSION: (name: string) => - `-- Drop extension\nDROP EXTENSION IF EXISTS "${name}" CASCADE;` - }, - SELECT: { - ALL: (schema: string, table: string, limit: number = 100) => - `SELECT * FROM ${schema}.${table} LIMIT ${limit};`, - WITH_WHERE: (schema: string, table: string, limit: number = 100) => - `SELECT * FROM ${schema}.${table}\nWHERE condition\nLIMIT ${limit};` - }, - COMMENT: { - TABLE: (schema: string, name: string, comment: string) => - `COMMENT ON TABLE ${schema}.${name} IS '${comment.replace(/'/g, "''")}';`, - COLUMN: (schema: string, table: string, column: string, comment: string) => - `COMMENT ON COLUMN ${schema}.${table}.${column} IS '${comment.replace(/'/g, "''")}';`, - VIEW: (schema: string, name: string, comment: string) => - `COMMENT ON VIEW ${schema}.${name} IS '${comment.replace(/'/g, "''")}';`, - FUNCTION: (schema: string, name: string, args: string, comment: string) => - `COMMENT ON FUNCTION ${schema}.${name}(${args}) IS '${comment.replace(/'/g, "''")}';`, - TYPE: (schema: string, name: string, comment: string) => - `COMMENT ON TYPE ${schema}.${name} IS '${comment.replace(/'/g, "''")}';` - } -}; - /** * Markdown formatting utilities */ @@ -214,956 +175,6 @@ export const ObjectUtils = { } }; - - -/** - * Common SQL query builders - */ -export const QueryBuilder = { - /** - * Build object information query - */ - objectInfo: (objectType: 'table' | 'view' | 'function' | 'type', schema: string, name: string): string => { - const queries = { - table: `SELECT * FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = '${name}';`, - view: `SELECT * FROM information_schema.views WHERE table_schema = '${schema}' AND table_name = '${name}';`, - function: `SELECT * FROM information_schema.routines WHERE routine_schema = '${schema}' AND routine_name = '${name}';`, - type: `SELECT * FROM information_schema.user_defined_types WHERE user_defined_type_schema = '${schema}' AND user_defined_type_name = '${name}';` - }; - return queries[objectType]; - }, - - /** - * Build privileges query - */ - privileges: (schema: string, objectName: string): string => - `SELECT - grantee, - privilege_type, - is_grantable -FROM information_schema.table_privileges -WHERE table_schema = '${schema}' - AND table_name = '${objectName}' -ORDER BY grantee, privilege_type;`, - - /** - * Build dependencies query - */ - dependencies: (schema: string, objectName: string): string => - `SELECT DISTINCT - dependent_ns.nspname as schema, - dependent_view.relname as name, - dependent_view.relkind as kind -FROM pg_depend -JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid -JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid -JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace -WHERE pg_depend.refobjid = '${schema}.${objectName}'::regclass -AND dependent_view.relname != '${objectName}' -ORDER BY schema, name;`, - - /** - * Build columns query - */ - columns: (schema: string, table: string): string => - `SELECT column_name, data_type, is_nullable, column_default -FROM information_schema.columns -WHERE table_schema = '${schema}' -AND table_name = '${table}' -ORDER BY ordinal_position;`, - - /** - * Build table columns query (detailed) - */ - tableColumns: (schema: string, table: string): string => - `SELECT - column_name, - data_type, - character_maximum_length, - numeric_precision, - numeric_scale, - is_nullable, - column_default, - ordinal_position, - col_description((table_schema||'.'||table_name)::regclass::oid, ordinal_position) as description -FROM information_schema.columns -WHERE table_schema = '${schema}' AND table_name = '${table}' -ORDER BY ordinal_position`, - - /** - * Build detailed constraint information query - */ - constraintDetails: (schema: string, table: string, constraint: string): string => ` - SELECT - tc.constraint_name, - tc.constraint_type, - tc.table_schema, - tc.table_name, - tc.is_deferrable, - tc.initially_deferred, - string_agg(kcu.column_name, ', ' ORDER BY kcu.ordinal_position) as columns, - cc.check_clause, - pg_get_constraintdef(con.oid) as constraint_definition, - obj_description(con.oid) as comment - FROM information_schema.table_constraints tc - LEFT JOIN information_schema.key_column_usage kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema - LEFT JOIN information_schema.check_constraints cc - ON tc.constraint_name = cc.constraint_name - AND tc.constraint_schema = cc.constraint_schema - LEFT JOIN pg_constraint con ON con.conname = tc.constraint_name - AND con.connamespace = (SELECT oid FROM pg_namespace WHERE nspname = tc.constraint_schema) - WHERE tc.constraint_name = '${constraint}' - AND tc.table_schema = '${schema}' - AND tc.table_name = '${table}' - GROUP BY tc.constraint_name, tc.constraint_type, tc.table_schema, tc.table_name, - tc.is_deferrable, tc.initially_deferred, cc.check_clause, con.oid - `, - - /** - * Build foreign key details query - */ - foreignKeyDetails: (schema: string, constraint: string): string => ` - SELECT - kcu.column_name, - ccu.table_schema as foreign_table_schema, - ccu.table_name as foreign_table_name, - ccu.column_name as foreign_column_name, - rc.update_rule, - rc.delete_rule - FROM information_schema.table_constraints tc - JOIN information_schema.key_column_usage kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema - JOIN information_schema.constraint_column_usage ccu - ON tc.constraint_name = ccu.constraint_name - AND tc.table_schema = ccu.constraint_schema - JOIN information_schema.referential_constraints rc - ON tc.constraint_name = rc.constraint_name - AND tc.table_schema = rc.constraint_schema - WHERE tc.constraint_name = '${constraint}' - AND tc.table_schema = '${schema}' - ORDER BY kcu.ordinal_position - `, - columnDetails: (schema: string, table: string, column: string): string => ` - SELECT - c.column_name, - c.data_type, - c.character_maximum_length, - c.numeric_precision, - c.numeric_scale, - c.is_nullable, - c.column_default, - c.udt_name, - c.ordinal_position, - col_description((c.table_schema||'.'||c.table_name)::regclass::oid, c.ordinal_position) as column_comment, - CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_key, - CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as is_foreign_key, - fk.foreign_table_schema, - fk.foreign_table_name, - fk.foreign_column_name, - CASE WHEN uq.column_name IS NOT NULL THEN true ELSE false END as is_unique - FROM information_schema.columns c - LEFT JOIN ( - SELECT ku.column_name, ku.table_schema, ku.table_name - FROM information_schema.table_constraints tc - JOIN information_schema.key_column_usage ku - ON tc.constraint_name = ku.constraint_name - AND tc.table_schema = ku.table_schema - WHERE tc.constraint_type = 'PRIMARY KEY' - ) pk ON c.column_name = pk.column_name - AND c.table_schema = pk.table_schema - AND c.table_name = pk.table_name - LEFT JOIN ( - SELECT - kcu.column_name, - kcu.table_schema, - kcu.table_name, - ccu.table_schema AS foreign_table_schema, - ccu.table_name AS foreign_table_name, - ccu.column_name AS foreign_column_name - FROM information_schema.table_constraints AS tc - JOIN information_schema.key_column_usage AS kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema - JOIN information_schema.constraint_column_usage AS ccu - ON ccu.constraint_name = tc.constraint_name - AND ccu.table_schema = tc.table_schema - WHERE tc.constraint_type = 'FOREIGN KEY' - ) fk ON c.column_name = fk.column_name - AND c.table_schema = fk.table_schema - AND c.table_name = fk.table_name - LEFT JOIN ( - SELECT ku.column_name, ku.table_schema, ku.table_name - FROM information_schema.table_constraints tc - JOIN information_schema.key_column_usage ku - ON tc.constraint_name = ku.constraint_name - AND tc.table_schema = ku.table_schema - WHERE tc.constraint_type = 'UNIQUE' - ) uq ON c.column_name = uq.column_name - AND c.table_schema = uq.table_schema - AND c.table_name = uq.table_name - WHERE c.table_schema = '${schema}' - AND c.table_name = '${table}' - AND c.column_name = '${column}' - `, - - /** - * Build table indexes query - */ - tableIndexes: (schema: string, table: string): string => - `SELECT - i.relname as index_name, - ix.indisunique as is_unique, - ix.indisprimary as is_primary, - string_agg(a.attname, ', ' ORDER BY a.attnum) as columns, - pg_get_indexdef(i.oid) as definition, - pg_size_pretty(pg_relation_size(i.oid)) as index_size -FROM pg_index ix -JOIN pg_class i ON i.oid = ix.indexrelid -JOIN pg_class t ON t.oid = ix.indrelid -JOIN pg_namespace n ON n.oid = t.relnamespace -JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) -WHERE n.nspname = '${schema}' AND t.relname = '${table}' -GROUP BY i.relname, ix.indisunique, ix.indisprimary, i.oid -ORDER BY ix.indisprimary DESC, ix.indisunique DESC, i.relname`, - - /** - * Build table constraints query - */ - tableConstraints: (schema: string, table: string): string => - `SELECT - tc.constraint_name, - tc.constraint_type, - string_agg(kcu.column_name, ', ' ORDER BY kcu.ordinal_position) as columns, - CASE - WHEN tc.constraint_type = 'FOREIGN KEY' THEN - ccu.table_schema || '.' || ccu.table_name - ELSE NULL - END as referenced_table -FROM information_schema.table_constraints tc -LEFT JOIN information_schema.key_column_usage kcu - ON tc.constraint_name = kcu.constraint_name - AND tc.table_schema = kcu.table_schema -LEFT JOIN information_schema.constraint_column_usage ccu - ON tc.constraint_name = ccu.constraint_name - AND tc.table_schema = ccu.constraint_schema -WHERE tc.table_schema = '${schema}' AND tc.table_name = '${table}' -GROUP BY tc.constraint_name, tc.constraint_type, ccu.table_schema, ccu.table_name -ORDER BY tc.constraint_type, tc.constraint_name`, - - /** - * Build table constraint definitions query - */ - tableConstraintDefinitions: (schema: string, table: string): string => - `SELECT - conname as constraint_name, - contype as constraint_type, - pg_get_constraintdef(c.oid) as definition -FROM pg_constraint c -JOIN pg_namespace n ON n.oid = c.connamespace -WHERE n.nspname = '${schema}' AND c.conrelid = '${schema}.${table}'::regclass -ORDER BY contype DESC, conname`, - - /** - * Build table statistics query - */ - tableStats: (schema: string, table: string): string => - `SELECT - n_live_tup as live_tuples, - n_dead_tup as dead_tuples, - n_mod_since_analyze as modifications_since_analyze, - last_vacuum, - last_autovacuum, - last_analyze, - last_autoanalyze, - vacuum_count, - autovacuum_count, - analyze_count, - autoanalyze_count -FROM pg_stat_user_tables -WHERE schemaname = '${schema}' AND relname = '${table}'`, - - /** - * Build table size query - */ - tableSize: (schema: string, table: string): string => - `SELECT - pg_size_pretty(pg_total_relation_size('${schema}.${table}'::regclass)) as total_size, - pg_size_pretty(pg_relation_size('${schema}.${table}'::regclass)) as table_size, - pg_size_pretty(pg_indexes_size('${schema}.${table}'::regclass)) as indexes_size, - pg_size_pretty(pg_total_relation_size('${schema}.${table}'::regclass) - pg_relation_size('${schema}.${table}'::regclass)) as toast_size`, - - /** - * Build table info query - */ - tableInfo: (schema: string, table: string): string => - `SELECT - c.relname as table_name, - n.nspname as schema_name, - pg_catalog.pg_get_userbyid(c.relowner) as owner, - obj_description(c.oid) as comment, - c.reltuples::bigint as row_estimate, - c.relpages as page_count, - c.relhasindex as has_indexes, - c.relispartition as is_partition -FROM pg_class c -JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE n.nspname = '${schema}' AND c.relname = '${table}'`, - - /** - * Build view definition query - */ - viewDefinition: (schema: string, view: string): string => - `SELECT pg_get_viewdef('${schema}.${view}'::regclass, true) as definition`, - - /** - * Build view info query - */ - viewInfo: (schema: string, view: string): string => - `SELECT - c.relname as view_name, - n.nspname as schema_name, - pg_catalog.pg_get_userbyid(c.relowner) as owner, - obj_description(c.oid) as comment, - c.reltuples::bigint as row_estimate -FROM pg_class c -JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE n.nspname = '${schema}' AND c.relname = '${view}' AND c.relkind = 'v'`, - - /** - * Build view size query - */ - viewSize: (schema: string, view: string): string => - `SELECT - pg_size_pretty(pg_relation_size('${schema}.${view}'::regclass)) as view_size`, - - - - /** - * Build type info query - */ - typeInfo: (schema: string, type: string): string => - `SELECT - t.typname as type_name, - n.nspname as schema_name, - pg_catalog.pg_get_userbyid(t.typowner) as owner, - obj_description(t.oid, 'pg_type') as description, - CASE t.typtype - WHEN 'c' THEN 'composite' - WHEN 'e' THEN 'enum' - WHEN 'r' THEN 'range' - ELSE t.typtype::text - END as type_type, - a.attname, - pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type, - a.attnum as ordinal_position -FROM pg_type t -JOIN pg_roles r ON t.typowner = r.oid -JOIN pg_class c ON c.oid = t.typrelid -JOIN pg_attribute a ON a.attrelid = c.oid -JOIN pg_namespace n ON n.oid = t.typnamespace -WHERE t.typname = '${type}' -AND n.nspname = '${schema}' -AND a.attnum > 0 -ORDER BY a.attnum`, - - /** - * Build type fields query - */ - typeFields: (schema: string, type: string): string => - `SELECT - t.typname, - a.attname, - pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type -FROM pg_type t -JOIN pg_class c ON c.oid = t.typrelid -JOIN pg_attribute a ON a.attrelid = c.oid -JOIN pg_namespace n ON n.oid = t.typnamespace -WHERE t.typname = '${type}' -AND n.nspname = '${schema}' -AND a.attnum > 0 -ORDER BY a.attnum`, - - - - /** - * Build role details query - */ - roleDetails: (roleName: string): string => - `WITH RECURSIVE -role_memberships AS ( - SELECT - r.rolname, - r.rolsuper, - r.rolinherit, - r.rolcreaterole, - r.rolcreatedb, - r.rolcanlogin, - r.rolreplication, - r.rolconnlimit, - r.rolvaliduntil, - r.rolbypassrls, - ( - SELECT array_agg(gr.rolname) - FROM pg_auth_members m - JOIN pg_roles gr ON gr.oid = m.roleid - WHERE m.member = r.oid - ) as member_of, - ( - SELECT array_agg(gr.rolname) - FROM pg_auth_members m - JOIN pg_roles gr ON gr.oid = m.member - WHERE m.roleid = r.oid - ) as members - FROM pg_roles r - WHERE r.rolname = '${roleName}' -), -role_privileges AS ( - SELECT array_agg( - privilege_type || ' ON ' || - CASE - WHEN table_schema = 'public' THEN table_name - ELSE table_schema || '.' || table_name - END - ) as privileges - FROM information_schema.table_privileges - WHERE grantee = '${roleName}' - GROUP BY grantee -), -database_access AS ( - SELECT array_agg(quote_ident(d.datname)) as databases - FROM pg_database d - JOIN pg_roles r ON r.rolname = '${roleName}' - WHERE EXISTS ( - SELECT 1 FROM aclexplode(d.datacl) acl - WHERE acl.grantee = r.oid - AND acl.privilege_type = 'CONNECT' - ) -) -SELECT - rm.*, - COALESCE(rp.privileges, ARRAY[]::text[]) as privileges, - COALESCE(da.databases, ARRAY[]::text[]) as accessible_databases -FROM role_memberships rm -LEFT JOIN role_privileges rp ON true -LEFT JOIN database_access da ON true`, - - /** - * Build role attributes query - */ - roleAttributes: (roleName: string): string => - `SELECT - r.rolname, - r.rolsuper, - r.rolinherit, - r.rolcreaterole, - r.rolcreatedb, - r.rolcanlogin, - r.rolreplication, - r.rolconnlimit, - r.rolvaliduntil, - r.rolbypassrls, - pg_catalog.shobj_description(r.oid, 'pg_authid') as description -FROM pg_roles r -WHERE r.rolname = '${roleName}'`, - - /** - * Build function info query - */ - functionInfo: (schema: string, name: string): string => - `SELECT p.proname, - pg_get_function_arguments(p.oid) as arguments, - pg_get_function_result(p.oid) as result_type, - pg_get_functiondef(p.oid) as definition, - d.description -FROM pg_proc p -LEFT JOIN pg_description d ON p.oid = d.objoid -WHERE p.proname = '${name}' -AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, - - /** - * Build function definition query - */ - functionDefinition: (schema: string, name: string): string => - `SELECT pg_get_functiondef(p.oid) as definition -FROM pg_proc p -WHERE p.proname = '${name}' -AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, - - /** - * Build function signature query - */ - functionSignature: (schema: string, name: string): string => - `SELECT p.proname, - pg_get_function_arguments(p.oid) as arguments, - pg_get_function_result(p.oid) as result_type, - d.description -FROM pg_proc p -LEFT JOIN pg_description d ON p.oid = d.objoid -WHERE p.proname = '${name}' -AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, - - /** - * Build function arguments query - */ - functionArguments: (schema: string, name: string): string => - `SELECT pg_get_function_arguments(p.oid) as arguments -FROM pg_proc p -WHERE p.proname = '${name}' -AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, - - /** - * Build schema info query - */ - schemaInfo: (schema: string): string => - `SELECT - n.nspname as schema_name, - pg_catalog.pg_get_userbyid(n.nspowner) as owner, - pg_size_pretty(sum(pg_total_relation_size(quote_ident(pg_tables.schemaname) || '.' || quote_ident(tablename))):: bigint) as total_size, - count(distinct tablename) as tables_count, - count(distinct viewname) as views_count, - count(distinct routines.routine_name) as functions_count, - array_agg(distinct format( - E'%s ON %s TO %s', - p.privilege_type, - p.table_schema, - p.grantee - )) as privileges -FROM pg_catalog.pg_namespace n -LEFT JOIN pg_tables ON pg_tables.schemaname = n.nspname -LEFT JOIN pg_views ON pg_tables.schemaname = n.nspname -LEFT JOIN information_schema.routines ON routine_schema = n.nspname -LEFT JOIN information_schema.table_privileges p ON p.table_schema = n.nspname -WHERE n.nspname = '${schema}' -GROUP BY n.nspname, n.nspowner`, - - /** - * Build schema details query - */ - schemaDetails: (schema: string): string => - `SELECT - n.nspname as schema_name, - pg_catalog.pg_get_userbyid(n.nspowner) as owner, - obj_description(n.oid, 'pg_namespace') as comment, - n.nspacl as acl -FROM pg_catalog.pg_namespace n -WHERE n.nspname = '${schema}'`, - - /** - * Build schema object counts query - */ - schemaObjectCounts: (schema: string): string => - `SELECT - COUNT(*) FILTER (WHERE c.relkind = 'r') as table_count, - COUNT(*) FILTER (WHERE c.relkind = 'v') as view_count, - COUNT(*) FILTER (WHERE c.relkind = 'm') as matview_count, - COUNT(*) FILTER (WHERE c.relkind = 'S') as sequence_count, - COUNT(*) FILTER (WHERE c.relkind = 'f') as foreign_table_count, - COUNT(*) FILTER (WHERE c.relkind = 'p') as partitioned_table_count, - (SELECT COUNT(*) FROM pg_proc p WHERE p.pronamespace = n.oid) as function_count, - (SELECT COUNT(*) FROM pg_type t WHERE t.typnamespace = n.oid AND t.typtype = 'c') as type_count, - (SELECT COUNT(*) FROM pg_trigger t - JOIN pg_class tc ON t.tgrelid = tc.oid - WHERE tc.relnamespace = n.oid AND NOT t.tgisinternal) as trigger_count -FROM pg_namespace n -LEFT JOIN pg_class c ON c.relnamespace = n.oid -WHERE n.nspname = '${schema}' -GROUP BY n.oid`, - - /** - * Build schema size query - */ - schemaSize: (schema: string): string => - `SELECT - pg_size_pretty(sum(pg_total_relation_size(c.oid))) as total_size, - pg_size_pretty(sum(pg_relation_size(c.oid))) as table_size, - pg_size_pretty(sum(pg_indexes_size(c.oid))) as indexes_size, - count(distinct c.oid) as relation_count -FROM pg_class c -JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE n.nspname = '${schema}' AND c.relkind IN ('r', 'i', 'm', 'S', 't')`, - - /** - * Build schema privileges query - */ - schemaPrivileges: (schema: string): string => - `SELECT - grantee, - string_agg(DISTINCT privilege_type, ', ' ORDER BY privilege_type) as privileges, - string_agg(DISTINCT - CASE WHEN is_grantable = 'YES' THEN privilege_type || ' (grantable)' END, - ', ') as grantable_privileges -FROM ( - SELECT DISTINCT grantee, privilege_type, is_grantable - FROM information_schema.table_privileges - WHERE table_schema = '${schema}' - UNION - SELECT DISTINCT grantee, privilege_type, is_grantable - FROM information_schema.routine_privileges - WHERE routine_schema = '${schema}' - UNION - SELECT DISTINCT grantee, privilege_type, is_grantable - FROM information_schema.usage_privileges - WHERE object_schema = '${schema}' -) p -GROUP BY grantee -ORDER BY grantee`, - - /** - * Build schema extensions query - */ - schemaExtensions: (schema: string): string => - `SELECT - e.extname as extension_name, - e.extversion as version, - pg_catalog.pg_get_userbyid(e.extowner) as owner -FROM pg_extension e -JOIN pg_namespace n ON n.oid = e.extnamespace -WHERE n.nspname = '${schema}'`, - - /** - * Build schema dependencies query - */ - schemaDependencies: (schema: string): string => - `SELECT - c.relname as object_name, - CASE c.relkind - WHEN 'r' THEN 'table' - WHEN 'v' THEN 'view' - WHEN 'm' THEN 'materialized view' - WHEN 'S' THEN 'sequence' - WHEN 'f' THEN 'foreign table' - WHEN 'p' THEN 'partitioned table' - END as object_type, - pg_size_pretty(pg_total_relation_size(c.oid)) as size -FROM pg_class c -JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE n.nspname = '${schema}' -AND c.relkind IN ('r', 'v', 'm', 'S', 'f', 'p') -ORDER BY pg_total_relation_size(c.oid) DESC -LIMIT 10`, - - /** - * Build schema all objects query - */ - schemaAllObjects: (schema: string): string => - `SELECT - CASE c.relkind - WHEN 'r' THEN 'table' - WHEN 'v' THEN 'view' - WHEN 'm' THEN 'materialized view' - WHEN 'i' THEN 'index' - WHEN 'S' THEN 'sequence' - WHEN 's' THEN 'special' - WHEN 'f' THEN 'foreign table' - WHEN 'p' THEN 'partitioned table' - END as object_type, - c.relname as object_name, - pg_size_pretty(pg_total_relation_size(quote_ident('${schema}') || '.' || quote_ident(c.relname))) as size, - CASE WHEN c.relkind = 'r' THEN - (SELECT reltuples::bigint FROM pg_class WHERE oid = c.oid) - ELSE NULL END as estimated_row_count, - pg_catalog.pg_get_userbyid(c.relowner) as owner -FROM pg_class c -JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE n.nspname = '${schema}' - AND c.relkind IN ('r', 'v', 'm', 'S', 'f', 'p') -ORDER BY pg_total_relation_size(c.oid) DESC NULLS LAST`, - - /** - * Build extension objects query - */ - extensionObjects: (extensionName: string): string => - `SELECT * FROM pg_catalog.pg_depend d - JOIN pg_catalog.pg_extension e ON d.refobjid = e.oid - JOIN pg_catalog.pg_class c ON d.objid = c.oid - WHERE e.extname = '${extensionName}' - AND d.deptype = 'e'`, - - /** - * Build foreign table info query - */ - foreignTableInfo: (schema: string, table: string): string => - `SELECT - c.column_name, - c.data_type, - c.is_nullable, - c.column_default, - fs.srvname as server_name, - fto.ftoptions as options -FROM information_schema.columns c -JOIN pg_class pc ON pc.relname = c.table_name -JOIN pg_foreign_table ft ON ft.ftrelid = pc.oid -JOIN pg_foreign_server fs ON fs.oid = ft.ftserver -LEFT JOIN pg_foreign_table_options fto ON fto.ftrelid = ft.ftrelid -WHERE c.table_schema = '${schema}' -AND c.table_name = '${table}' -ORDER BY c.ordinal_position`, - - /** - * Build foreign table definition query - */ - foreignTableDefinition: (schema: string, table: string): string => - `SELECT - c.relname as table_name, - fs.srvname as server_name, - array_agg( - format('%I %s%s', - a.attname, - format_type(a.atttypid, a.atttypmod), - CASE WHEN a.attnotnull THEN ' NOT NULL' ELSE '' END - ) ORDER BY a.attnum - ) as columns, - ftoptions as options -FROM pg_class c -JOIN pg_foreign_table ft ON c.oid = ft.ftrelid -JOIN pg_foreign_server fs ON fs.oid = ft.ftserver -JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 -LEFT JOIN pg_foreign_table_options fto ON fto.ftrelid = ft.ftrelid -JOIN pg_namespace n ON n.oid = c.relnamespace -WHERE c.relname = '${table}' -AND n.nspname = '${schema}' -GROUP BY c.relname, fs.srvname, ftoptions`, - - /** - * Build materialized view info query - */ - matViewInfo: (schema: string, view: string): string => - `SELECT pg_get_viewdef('${schema}.${view}'::regclass, true) as definition, - schemaname, - matviewname, - matviewowner, - tablespace, - hasindexes, - ispopulated, - pg_size_pretty(pg_total_relation_size(format('%I.%I', schemaname, matviewname))) as size -FROM pg_matviews -WHERE schemaname = '${schema}' AND matviewname = '${view}'`, - - /** - * Build materialized view definition query - */ - matViewDefinition: (schema: string, view: string): string => - `SELECT pg_get_viewdef('${schema}.${view}'::regclass, true) as definition -FROM pg_matviews -WHERE schemaname = '${schema}' AND matviewname = '${view}'`, - - /** - * Build materialized view stats query - */ - matViewStats: (schema: string, view: string): string => - `SELECT - n_live_tup as live_tuples, - n_dead_tup as dead_tuples, - last_vacuum, - last_autovacuum, - last_analyze, - last_autoanalyze -FROM pg_stat_user_tables -WHERE schemaname = '${schema}' AND relname = '${view}'`, - - /** - * Build object dependencies query - */ - objectDependencies: (schema: string, name: string): string => - `SELECT DISTINCT - dependent_ns.nspname as schema, - dependent_view.relname as name, - dependent_view.relkind as kind -FROM pg_depend -JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid -JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid -JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace -WHERE pg_depend.refobjid = '${schema}.${name}'::regclass -AND dependent_view.relname != '${name}' -ORDER BY schema, name`, - - /** - * Build object references query - */ - objectReferences: (schema: string, name: string): string => - `SELECT DISTINCT - ref_nsp.nspname as schema, - ref_class.relname as name, - ref_class.relkind as kind -FROM pg_depend dep -JOIN pg_rewrite rew ON dep.objid = rew.oid -JOIN pg_class ref_class ON dep.refobjid = ref_class.oid -JOIN pg_namespace ref_nsp ON ref_nsp.oid = ref_class.relnamespace -WHERE rew.ev_class = '${schema}.${name}'::regclass -AND ref_class.relname != '${name}' -AND ref_class.relkind IN ('r', 'v', 'm') -ORDER BY schema, name`, - - /** - * Build database statistics query - */ - databaseStats: (): string => - `SELECT - d.datname as "Database", - pg_size_pretty(pg_database_size(d.datname)) as "Size", - u.usename as "Owner", - (SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()) as "Active Connections", - (SELECT count(*) FROM pg_namespace WHERE nspname NOT IN ('pg_catalog', 'information_schema')) as "Schemas", - (SELECT count(*) FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema')) as "Tables", - (SELECT count(*) FROM pg_roles) as "Roles" -FROM pg_database d -JOIN pg_user u ON d.datdba = u.usesysid -WHERE d.datname = current_database()`, - - /** - * Build database schema sizes query - */ - databaseSchemaSizes: (): string => - `SELECT - pg_tables.schemaname as schema_name, - pg_total_relation_size(pg_tables.schemaname || '.' || tablename) as table_size -FROM pg_tables -WHERE pg_tables.schemaname NOT IN ('pg_catalog', 'information_schema')`, - - /** - * Build database schema size summary query - */ - databaseSchemaSizeSummary: (): string => - `SELECT schema_name, - pg_size_pretty(sum(table_size)::bigint) as "Size", - count(table_name) as "Tables" -FROM ( - SELECT pg_tables.schemaname as schema_name, - tablename as table_name, - pg_total_relation_size(pg_tables.schemaname || '.' || tablename) as table_size - FROM pg_tables -) t -GROUP BY schema_name -ORDER BY sum(table_size) DESC`, - - /** - * Build database maintenance stats query - */ - databaseMaintenanceStats: (): string => - `SELECT - schemaname || '.' || relname as "Table", - n_dead_tup as "Dead Tuples", - n_live_tup as "Live Tuples", - last_vacuum as "Last Vacuum", - last_autovacuum as "Last Auto Vacuum", - pg_size_pretty(pg_total_relation_size(schemaname || '.' || relname)) as "Total Size" -FROM pg_stat_user_tables -WHERE n_dead_tup > 0 -ORDER BY n_dead_tup DESC -LIMIT 20`, - - /** - * Build database configuration query - */ - databaseConfiguration: (): string => - `SELECT - name as "Setting", - setting as "Value", - unit as "Unit", - category as "Category", - short_desc as "Description" -FROM pg_settings -ORDER BY category, name`, - - /** - * Build database memory settings query - */ - databaseMemorySettings: (): string => - `SELECT - name as "Setting", - setting as "Value", - unit as "Unit", - short_desc as "Description" -FROM pg_settings -WHERE category LIKE '%Memory%' OR name LIKE '%memory%' OR name LIKE '%buffer%' -ORDER BY name`, - - /** - * Build database connection settings query - */ - databaseConnectionSettings: (): string => - `SELECT - name as "Setting", - setting as "Value", - unit as "Unit", - short_desc as "Description" -FROM pg_settings -WHERE category LIKE '%Connection%' OR name LIKE '%connection%' -ORDER BY name`, - - /** - * Build database active connections query - */ - databaseActiveConnections: (): string => - `SELECT pid as "Process ID", - usename as "User", - datname as "Database", - client_addr as "Client Address", - application_name as "Application", - state as "State", - query as "Last Query", - backend_start as "Connected Since" -FROM pg_stat_activity -WHERE datname = current_database() -ORDER BY backend_start`, - - /** - * Build database extensions query - */ - databaseExtensions: (): string => - `SELECT name as "Extension", - default_version as "Default Version", - installed_version as "Installed Version", - comment as "Description" -FROM pg_available_extensions -WHERE installed_version IS NOT NULL -ORDER BY name`, - - /** - * Build database roles query - */ - databaseRoles: (): string => - `SELECT - r.rolname as "Role", - r.rolsuper as "Superuser", - r.rolcreatedb as "Create DB", - r.rolcreaterole as "Create Role", - r.rolcanlogin as "Can Login", - r.rolconnlimit as "Connection Limit", - r.rolvaliduntil as "Valid Until" -FROM pg_roles r -ORDER BY r.rolname`, - - /** - * Build terminate connections query - */ - databaseTerminateConnections: (databaseName?: string): string => { - const dbFilter = databaseName ? `WHERE datname = '${databaseName}'` : `WHERE datname = current_database()`; - return `SELECT format( - 'SELECT pg_terminate_backend(%s) /* %s %s %s */;', - pid, - usename, - application_name, - query -) -FROM pg_stat_activity -${dbFilter} -AND pid <> pg_backend_pid();`; - }, - - /** - * Build terminate connections by PID query - */ - terminateConnectionsByPid: (databaseName: string): string => - `SELECT pg_terminate_backend(pid) -FROM pg_stat_activity -WHERE datname = '${databaseName}' - AND pid <> pg_backend_pid();` -}; - /** * Format helpers for displaying data */ @@ -1242,29 +253,6 @@ export const ValidationHelpers = { } }; -/** - * Common maintenance operations - */ -export const MaintenanceTemplates = { - vacuum: (schema: string, table: string): string => - `-- Vacuum table\nVACUUM (VERBOSE, ANALYZE) ${schema}.${table};`, - - analyze: (schema: string, table: string): string => - `-- Analyze table\nANALYZE VERBOSE ${schema}.${table};`, - - reindex: (schema: string, table: string): string => - `-- Reindex table\nREINDEX TABLE ${schema}.${table};`, - - vacuumFull: (schema: string, table: string): string => - `-- Vacuum full (locks table)\nVACUUM FULL ${schema}.${table};`, - - vacuumAnalyzeDatabase: (): string => - `-- Vacuum and update statistics (safe, non-blocking)\nVACUUM (VERBOSE, ANALYZE);`, - - reindexDatabase: (databaseName: string): string => - `-- Reindex entire database (locks tables during rebuild)\n-- REINDEX DATABASE "${databaseName}";` -}; - /** * Common error handling patterns */ diff --git a/src/commands/sql/helper.ts b/src/commands/sql/helper.ts new file mode 100644 index 0000000..1ebde31 --- /dev/null +++ b/src/commands/sql/helper.ts @@ -0,0 +1,1018 @@ +/** + * SQL Templates from Helper Module + * Contains SQL templates, query builders, and maintenance templates + * that were previously in helpers/helper.ts + */ + +/** + * Common SQL query templates + */ +export const SQL_TEMPLATES = { + DROP: { + TABLE: (schema: string, name: string) => + `-- Drop table\nDROP TABLE IF EXISTS "${schema}"."${name}";`, + VIEW: (schema: string, name: string) => + `-- Drop view\nDROP VIEW IF EXISTS ${schema}.${name};`, + MATERIALIZED_VIEW: (schema: string, name: string) => + `-- Drop materialized view\nDROP MATERIALIZED VIEW IF EXISTS ${schema}.${name};`, + FUNCTION: (schema: string, name: string, args: string) => + `-- Drop function\nDROP FUNCTION IF EXISTS ${schema}.${name}(${args});`, + INDEX: (schema: string, name: string) => + `-- Drop index\nDROP INDEX "${schema}"."${name}";`, + CONSTRAINT: (schema: string, table: string, name: string) => + `-- Drop constraint\nALTER TABLE "${schema}"."${table}"\nDROP CONSTRAINT "${name}";`, + TYPE: (schema: string, name: string) => + `-- Drop type\nDROP TYPE IF EXISTS ${schema}.${name} CASCADE;`, + EXTENSION: (name: string) => + `-- Drop extension\nDROP EXTENSION IF EXISTS "${name}" CASCADE;` + }, + SELECT: { + ALL: (schema: string, table: string, limit: number = 100) => + `SELECT * FROM ${schema}.${table} LIMIT ${limit};`, + WITH_WHERE: (schema: string, table: string, limit: number = 100) => + `SELECT * FROM ${schema}.${table}\nWHERE condition\nLIMIT ${limit};` + }, + COMMENT: { + TABLE: (schema: string, name: string, comment: string) => + `COMMENT ON TABLE ${schema}.${name} IS '${comment.replace(/'/g, "''")}';`, + COLUMN: (schema: string, table: string, column: string, comment: string) => + `COMMENT ON COLUMN ${schema}.${table}.${column} IS '${comment.replace(/'/g, "''")}';`, + VIEW: (schema: string, name: string, comment: string) => + `COMMENT ON VIEW ${schema}.${name} IS '${comment.replace(/'/g, "''")}';`, + FUNCTION: (schema: string, name: string, args: string, comment: string) => + `COMMENT ON FUNCTION ${schema}.${name}(${args}) IS '${comment.replace(/'/g, "''")}';`, + TYPE: (schema: string, name: string, comment: string) => + `COMMENT ON TYPE ${schema}.${name} IS '${comment.replace(/'/g, "''")}';` + } +}; + +/** + * Common SQL query builders + */ +export const QueryBuilder = { + /** + * Build object information query + */ + objectInfo: (objectType: 'table' | 'view' | 'function' | 'type', schema: string, name: string): string => { + const queries = { + table: `SELECT * FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = '${name}';`, + view: `SELECT * FROM information_schema.views WHERE table_schema = '${schema}' AND table_name = '${name}';`, + function: `SELECT * FROM information_schema.routines WHERE routine_schema = '${schema}' AND routine_name = '${name}';`, + type: `SELECT * FROM information_schema.user_defined_types WHERE user_defined_type_schema = '${schema}' AND user_defined_type_name = '${name}';` + }; + return queries[objectType]; + }, + + /** + * Build privileges query + */ + privileges: (schema: string, objectName: string): string => + `SELECT + grantee, + privilege_type, + is_grantable +FROM information_schema.table_privileges +WHERE table_schema = '${schema}' + AND table_name = '${objectName}' +ORDER BY grantee, privilege_type;`, + + /** + * Build dependencies query + */ + dependencies: (schema: string, objectName: string): string => + `SELECT DISTINCT + dependent_ns.nspname as schema, + dependent_view.relname as name, + dependent_view.relkind as kind +FROM pg_depend +JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid +JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid +JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace +WHERE pg_depend.refobjid = '${schema}.${objectName}'::regclass +AND dependent_view.relname != '${objectName}' +ORDER BY schema, name;`, + + /** + * Build columns query + */ + columns: (schema: string, table: string): string => + `SELECT column_name, data_type, is_nullable, column_default +FROM information_schema.columns +WHERE table_schema = '${schema}' +AND table_name = '${table}' +ORDER BY ordinal_position;`, + + /** + * Build table columns query (detailed) + */ + tableColumns: (schema: string, table: string): string => + `SELECT + column_name, + data_type, + character_maximum_length, + numeric_precision, + numeric_scale, + is_nullable, + column_default, + ordinal_position, + col_description((table_schema||'.'||table_name)::regclass::oid, ordinal_position) as description +FROM information_schema.columns +WHERE table_schema = '${schema}' AND table_name = '${table}' +ORDER BY ordinal_position`, + + /** + * Build detailed constraint information query + */ + constraintDetails: (schema: string, table: string, constraint: string): string => ` + SELECT + tc.constraint_name, + tc.constraint_type, + tc.table_schema, + tc.table_name, + tc.is_deferrable, + tc.initially_deferred, + string_agg(kcu.column_name, ', ' ORDER BY kcu.ordinal_position) as columns, + cc.check_clause, + pg_get_constraintdef(con.oid) as constraint_definition, + obj_description(con.oid) as comment + FROM information_schema.table_constraints tc + LEFT JOIN information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema + LEFT JOIN information_schema.check_constraints cc + ON tc.constraint_name = cc.constraint_name + AND tc.constraint_schema = cc.constraint_schema + LEFT JOIN pg_constraint con ON con.conname = tc.constraint_name + AND con.connamespace = (SELECT oid FROM pg_namespace WHERE nspname = tc.constraint_schema) + WHERE tc.constraint_name = '${constraint}' + AND tc.table_schema = '${schema}' + AND tc.table_name = '${table}' + GROUP BY tc.constraint_name, tc.constraint_type, tc.table_schema, tc.table_name, + tc.is_deferrable, tc.initially_deferred, cc.check_clause, con.oid + `, + + /** + * Build foreign key details query + */ + foreignKeyDetails: (schema: string, constraint: string): string => ` + SELECT + kcu.column_name, + ccu.table_schema as foreign_table_schema, + ccu.table_name as foreign_table_name, + ccu.column_name as foreign_column_name, + rc.update_rule, + rc.delete_rule + FROM information_schema.table_constraints tc + JOIN information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema + JOIN information_schema.constraint_column_usage ccu + ON tc.constraint_name = ccu.constraint_name + AND tc.table_schema = ccu.constraint_schema + JOIN information_schema.referential_constraints rc + ON tc.constraint_name = rc.constraint_name + AND tc.table_schema = rc.constraint_schema + WHERE tc.constraint_name = '${constraint}' + AND tc.table_schema = '${schema}' + ORDER BY kcu.ordinal_position + `, + columnDetails: (schema: string, table: string, column: string): string => ` + SELECT + c.column_name, + c.data_type, + c.character_maximum_length, + c.numeric_precision, + c.numeric_scale, + c.is_nullable, + c.column_default, + c.udt_name, + c.ordinal_position, + col_description((c.table_schema||'.'||c.table_name)::regclass::oid, c.ordinal_position) as column_comment, + CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_key, + CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as is_foreign_key, + fk.foreign_table_schema, + fk.foreign_table_name, + fk.foreign_column_name, + CASE WHEN uq.column_name IS NOT NULL THEN true ELSE false END as is_unique + FROM information_schema.columns c + LEFT JOIN ( + SELECT ku.column_name, ku.table_schema, ku.table_name + FROM information_schema.table_constraints tc + JOIN information_schema.key_column_usage ku + ON tc.constraint_name = ku.constraint_name + AND tc.table_schema = ku.table_schema + WHERE tc.constraint_type = 'PRIMARY KEY' + ) pk ON c.column_name = pk.column_name + AND c.table_schema = pk.table_schema + AND c.table_name = pk.table_name + LEFT JOIN ( + SELECT + kcu.column_name, + kcu.table_schema, + kcu.table_name, + ccu.table_schema AS foreign_table_schema, + ccu.table_name AS foreign_table_name, + ccu.column_name AS foreign_column_name + FROM information_schema.table_constraints AS tc + JOIN information_schema.key_column_usage AS kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema + JOIN information_schema.constraint_column_usage AS ccu + ON ccu.constraint_name = tc.constraint_name + AND ccu.table_schema = tc.table_schema + WHERE tc.constraint_type = 'FOREIGN KEY' + ) fk ON c.column_name = fk.column_name + AND c.table_schema = fk.table_schema + AND c.table_name = fk.table_name + LEFT JOIN ( + SELECT ku.column_name, ku.table_schema, ku.table_name + FROM information_schema.table_constraints tc + JOIN information_schema.key_column_usage ku + ON tc.constraint_name = ku.constraint_name + AND tc.table_schema = ku.table_schema + WHERE tc.constraint_type = 'UNIQUE' + ) uq ON c.column_name = uq.column_name + AND c.table_schema = uq.table_schema + AND c.table_name = uq.table_name + WHERE c.table_schema = '${schema}' + AND c.table_name = '${table}' + AND c.column_name = '${column}' + `, + + /** + * Build table indexes query + */ + tableIndexes: (schema: string, table: string): string => + `SELECT + i.relname as index_name, + ix.indisunique as is_unique, + ix.indisprimary as is_primary, + string_agg(a.attname, ', ' ORDER BY a.attnum) as columns, + pg_get_indexdef(i.oid) as definition, + pg_size_pretty(pg_relation_size(i.oid)) as index_size +FROM pg_index ix +JOIN pg_class i ON i.oid = ix.indexrelid +JOIN pg_class t ON t.oid = ix.indrelid +JOIN pg_namespace n ON n.oid = t.relnamespace +JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) +WHERE n.nspname = '${schema}' AND t.relname = '${table}' +GROUP BY i.relname, ix.indisunique, ix.indisprimary, i.oid +ORDER BY ix.indisprimary DESC, ix.indisunique DESC, i.relname`, + + /** + * Build table constraints query + */ + tableConstraints: (schema: string, table: string): string => + `SELECT + tc.constraint_name, + tc.constraint_type, + string_agg(kcu.column_name, ', ' ORDER BY kcu.ordinal_position) as columns, + CASE + WHEN tc.constraint_type = 'FOREIGN KEY' THEN + ccu.table_schema || '.' || ccu.table_name + ELSE NULL + END as referenced_table +FROM information_schema.table_constraints tc +LEFT JOIN information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + AND tc.table_schema = kcu.table_schema +LEFT JOIN information_schema.constraint_column_usage ccu + ON tc.constraint_name = ccu.constraint_name + AND tc.table_schema = ccu.constraint_schema +WHERE tc.table_schema = '${schema}' AND tc.table_name = '${table}' +GROUP BY tc.constraint_name, tc.constraint_type, ccu.table_schema, ccu.table_name +ORDER BY tc.constraint_type, tc.constraint_name`, + + /** + * Build table constraint definitions query + */ + tableConstraintDefinitions: (schema: string, table: string): string => + `SELECT + conname as constraint_name, + contype as constraint_type, + pg_get_constraintdef(c.oid) as definition +FROM pg_constraint c +JOIN pg_namespace n ON n.oid = c.connamespace +WHERE n.nspname = '${schema}' AND c.conrelid = '${schema}.${table}'::regclass +ORDER BY contype DESC, conname`, + + /** + * Build table statistics query + */ + tableStats: (schema: string, table: string): string => + `SELECT + n_live_tup as live_tuples, + n_dead_tup as dead_tuples, + n_mod_since_analyze as modifications_since_analyze, + last_vacuum, + last_autovacuum, + last_analyze, + last_autoanalyze, + vacuum_count, + autovacuum_count, + analyze_count, + autoanalyze_count +FROM pg_stat_user_tables +WHERE schemaname = '${schema}' AND relname = '${table}'`, + + /** + * Build table size query + */ + tableSize: (schema: string, table: string): string => + `SELECT + pg_size_pretty(pg_total_relation_size('${schema}.${table}'::regclass)) as total_size, + pg_size_pretty(pg_relation_size('${schema}.${table}'::regclass)) as table_size, + pg_size_pretty(pg_indexes_size('${schema}.${table}'::regclass)) as indexes_size, + pg_size_pretty(pg_total_relation_size('${schema}.${table}'::regclass) - pg_relation_size('${schema}.${table}'::regclass)) as toast_size`, + + /** + * Build table info query + */ + tableInfo: (schema: string, table: string): string => + `SELECT + c.relname as table_name, + n.nspname as schema_name, + pg_catalog.pg_get_userbyid(c.relowner) as owner, + obj_description(c.oid) as comment, + c.reltuples::bigint as row_estimate, + c.relpages as page_count, + c.relhasindex as has_indexes, + c.relispartition as is_partition +FROM pg_class c +JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE n.nspname = '${schema}' AND c.relname = '${table}'`, + + /** + * Build view definition query + */ + viewDefinition: (schema: string, view: string): string => + `SELECT pg_get_viewdef('${schema}.${view}'::regclass, true) as definition`, + + /** + * Build view info query + */ + viewInfo: (schema: string, view: string): string => + `SELECT + c.relname as view_name, + n.nspname as schema_name, + pg_catalog.pg_get_userbyid(c.relowner) as owner, + obj_description(c.oid) as comment, + c.reltuples::bigint as row_estimate +FROM pg_class c +JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE n.nspname = '${schema}' AND c.relname = '${view}' AND c.relkind = 'v'`, + + /** + * Build view size query + */ + viewSize: (schema: string, view: string): string => + `SELECT + pg_size_pretty(pg_relation_size('${schema}.${view}'::regclass)) as view_size`, + + + + /** + * Build type info query + */ + typeInfo: (schema: string, type: string): string => + `SELECT + t.typname as type_name, + n.nspname as schema_name, + pg_catalog.pg_get_userbyid(t.typowner) as owner, + obj_description(t.oid, 'pg_type') as description, + CASE t.typtype + WHEN 'c' THEN 'composite' + WHEN 'e' THEN 'enum' + WHEN 'r' THEN 'range' + ELSE t.typtype::text + END as type_type, + a.attname, + pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type, + a.attnum as ordinal_position +FROM pg_type t +JOIN pg_roles r ON t.typowner = r.oid +JOIN pg_class c ON c.oid = t.typrelid +JOIN pg_attribute a ON a.attrelid = c.oid +JOIN pg_namespace n ON n.oid = t.typnamespace +WHERE t.typname = '${type}' +AND n.nspname = '${schema}' +AND a.attnum > 0 +ORDER BY a.attnum`, + + /** + * Build type fields query + */ + typeFields: (schema: string, type: string): string => + `SELECT + t.typname, + a.attname, + pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type +FROM pg_type t +JOIN pg_class c ON c.oid = t.typrelid +JOIN pg_attribute a ON a.attrelid = c.oid +JOIN pg_namespace n ON n.oid = t.typnamespace +WHERE t.typname = '${type}' +AND n.nspname = '${schema}' +AND a.attnum > 0 +ORDER BY a.attnum`, + + + + /** + * Build role details query + */ + roleDetails: (roleName: string): string => + `WITH RECURSIVE +role_memberships AS ( + SELECT + r.rolname, + r.rolsuper, + r.rolinherit, + r.rolcreaterole, + r.rolcreatedb, + r.rolcanlogin, + r.rolreplication, + r.rolconnlimit, + r.rolvaliduntil, + r.rolbypassrls, + ( + SELECT array_agg(gr.rolname) + FROM pg_auth_members m + JOIN pg_roles gr ON gr.oid = m.roleid + WHERE m.member = r.oid + ) as member_of, + ( + SELECT array_agg(gr.rolname) + FROM pg_auth_members m + JOIN pg_roles gr ON gr.oid = m.member + WHERE m.roleid = r.oid + ) as members + FROM pg_roles r + WHERE r.rolname = '${roleName}' +), +role_privileges AS ( + SELECT array_agg( + privilege_type || ' ON ' || + CASE + WHEN table_schema = 'public' THEN table_name + ELSE table_schema || '.' || table_name + END + ) as privileges + FROM information_schema.table_privileges + WHERE grantee = '${roleName}' + GROUP BY grantee +), +database_access AS ( + SELECT array_agg(quote_ident(d.datname)) as databases + FROM pg_database d + JOIN pg_roles r ON r.rolname = '${roleName}' + WHERE EXISTS ( + SELECT 1 FROM aclexplode(d.datacl) acl + WHERE acl.grantee = r.oid + AND acl.privilege_type = 'CONNECT' + ) +) +SELECT + rm.*, + COALESCE(rp.privileges, ARRAY[]::text[]) as privileges, + COALESCE(da.databases, ARRAY[]::text[]) as accessible_databases +FROM role_memberships rm +LEFT JOIN role_privileges rp ON true +LEFT JOIN database_access da ON true`, + + /** + * Build role attributes query + */ + roleAttributes: (roleName: string): string => + `SELECT + r.rolname, + r.rolsuper, + r.rolinherit, + r.rolcreaterole, + r.rolcreatedb, + r.rolcanlogin, + r.rolreplication, + r.rolconnlimit, + r.rolvaliduntil, + r.rolbypassrls, + pg_catalog.shobj_description(r.oid, 'pg_authid') as description +FROM pg_roles r +WHERE r.rolname = '${roleName}'`, + + /** + * Build function info query + */ + functionInfo: (schema: string, name: string): string => + `SELECT p.proname, + pg_get_function_arguments(p.oid) as arguments, + pg_get_function_result(p.oid) as result_type, + pg_get_functiondef(p.oid) as definition, + d.description +FROM pg_proc p +LEFT JOIN pg_description d ON p.oid = d.objoid +WHERE p.proname = '${name}' +AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, + + /** + * Build function definition query + */ + functionDefinition: (schema: string, name: string): string => + `SELECT pg_get_functiondef(p.oid) as definition +FROM pg_proc p +WHERE p.proname = '${name}' +AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, + + /** + * Build function signature query + */ + functionSignature: (schema: string, name: string): string => + `SELECT p.proname, + pg_get_function_arguments(p.oid) as arguments, + pg_get_function_result(p.oid) as result_type, + d.description +FROM pg_proc p +LEFT JOIN pg_description d ON p.oid = d.objoid +WHERE p.proname = '${name}' +AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, + + /** + * Build function arguments query + */ + functionArguments: (schema: string, name: string): string => + `SELECT pg_get_function_arguments(p.oid) as arguments +FROM pg_proc p +WHERE p.proname = '${name}' +AND p.pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${schema}')`, + + /** + * Build schema info query + */ + schemaInfo: (schema: string): string => + `SELECT + n.nspname as schema_name, + pg_catalog.pg_get_userbyid(n.nspowner) as owner, + pg_size_pretty(sum(pg_total_relation_size(quote_ident(pg_tables.schemaname) || '.' || quote_ident(tablename))):: bigint) as total_size, + count(distinct tablename) as tables_count, + count(distinct viewname) as views_count, + count(distinct routines.routine_name) as functions_count, + array_agg(distinct format( + E'%s ON %s TO %s', + p.privilege_type, + p.table_schema, + p.grantee + )) as privileges +FROM pg_catalog.pg_namespace n +LEFT JOIN pg_tables ON pg_tables.schemaname = n.nspname +LEFT JOIN pg_views ON pg_tables.schemaname = n.nspname +LEFT JOIN information_schema.routines ON routine_schema = n.nspname +LEFT JOIN information_schema.table_privileges p ON p.table_schema = n.nspname +WHERE n.nspname = '${schema}' +GROUP BY n.nspname, n.nspowner`, + + /** + * Build schema details query + */ + schemaDetails: (schema: string): string => + `SELECT + n.nspname as schema_name, + pg_catalog.pg_get_userbyid(n.nspowner) as owner, + obj_description(n.oid, 'pg_namespace') as comment, + n.nspacl as acl +FROM pg_catalog.pg_namespace n +WHERE n.nspname = '${schema}'`, + + /** + * Build schema object counts query + */ + schemaObjectCounts: (schema: string): string => + `SELECT + COUNT(*) FILTER (WHERE c.relkind = 'r') as table_count, + COUNT(*) FILTER (WHERE c.relkind = 'v') as view_count, + COUNT(*) FILTER (WHERE c.relkind = 'm') as matview_count, + COUNT(*) FILTER (WHERE c.relkind = 'S') as sequence_count, + COUNT(*) FILTER (WHERE c.relkind = 'f') as foreign_table_count, + COUNT(*) FILTER (WHERE c.relkind = 'p') as partitioned_table_count, + (SELECT COUNT(*) FROM pg_proc p WHERE p.pronamespace = n.oid) as function_count, + (SELECT COUNT(*) FROM pg_type t WHERE t.typnamespace = n.oid AND t.typtype = 'c') as type_count, + (SELECT COUNT(*) FROM pg_trigger t + JOIN pg_class tc ON t.tgrelid = tc.oid + WHERE tc.relnamespace = n.oid AND NOT t.tgisinternal) as trigger_count +FROM pg_namespace n +LEFT JOIN pg_class c ON c.relnamespace = n.oid +WHERE n.nspname = '${schema}' +GROUP BY n.oid`, + + /** + * Build schema size query + */ + schemaSize: (schema: string): string => + `SELECT + pg_size_pretty(sum(pg_total_relation_size(c.oid))) as total_size, + pg_size_pretty(sum(pg_relation_size(c.oid))) as table_size, + pg_size_pretty(sum(pg_indexes_size(c.oid))) as indexes_size, + count(distinct c.oid) as relation_count +FROM pg_class c +JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE n.nspname = '${schema}' AND c.relkind IN ('r', 'i', 'm', 'S', 't')`, + + /** + * Build schema privileges query + */ + schemaPrivileges: (schema: string): string => + `SELECT + grantee, + string_agg(DISTINCT privilege_type, ', ' ORDER BY privilege_type) as privileges, + string_agg(DISTINCT + CASE WHEN is_grantable = 'YES' THEN privilege_type || ' (grantable)' END, + ', ') as grantable_privileges +FROM ( + SELECT DISTINCT grantee, privilege_type, is_grantable + FROM information_schema.table_privileges + WHERE table_schema = '${schema}' + UNION + SELECT DISTINCT grantee, privilege_type, is_grantable + FROM information_schema.routine_privileges + WHERE routine_schema = '${schema}' + UNION + SELECT DISTINCT grantee, privilege_type, is_grantable + FROM information_schema.usage_privileges + WHERE object_schema = '${schema}' +) p +GROUP BY grantee +ORDER BY grantee`, + + /** + * Build schema extensions query + */ + schemaExtensions: (schema: string): string => + `SELECT + e.extname as extension_name, + e.extversion as version, + pg_catalog.pg_get_userbyid(e.extowner) as owner +FROM pg_extension e +JOIN pg_namespace n ON n.oid = e.extnamespace +WHERE n.nspname = '${schema}'`, + + /** + * Build schema dependencies query + */ + schemaDependencies: (schema: string): string => + `SELECT + c.relname as object_name, + CASE c.relkind + WHEN 'r' THEN 'table' + WHEN 'v' THEN 'view' + WHEN 'm' THEN 'materialized view' + WHEN 'S' THEN 'sequence' + WHEN 'f' THEN 'foreign table' + WHEN 'p' THEN 'partitioned table' + END as object_type, + pg_size_pretty(pg_total_relation_size(c.oid)) as size +FROM pg_class c +JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE n.nspname = '${schema}' +AND c.relkind IN ('r', 'v', 'm', 'S', 'f', 'p') +ORDER BY pg_total_relation_size(c.oid) DESC +LIMIT 10`, + + /** + * Build schema all objects query + */ + schemaAllObjects: (schema: string): string => + `SELECT + CASE c.relkind + WHEN 'r' THEN 'table' + WHEN 'v' THEN 'view' + WHEN 'm' THEN 'materialized view' + WHEN 'i' THEN 'index' + WHEN 'S' THEN 'sequence' + WHEN 's' THEN 'special' + WHEN 'f' THEN 'foreign table' + WHEN 'p' THEN 'partitioned table' + END as object_type, + c.relname as object_name, + pg_size_pretty(pg_total_relation_size(quote_ident('${schema}') || '.' || quote_ident(c.relname))) as size, + CASE WHEN c.relkind = 'r' THEN + (SELECT reltuples::bigint FROM pg_class WHERE oid = c.oid) + ELSE NULL END as estimated_row_count, + pg_catalog.pg_get_userbyid(c.relowner) as owner +FROM pg_class c +JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE n.nspname = '${schema}' + AND c.relkind IN ('r', 'v', 'm', 'S', 'f', 'p') +ORDER BY pg_total_relation_size(c.oid) DESC NULLS LAST`, + + /** + * Build extension objects query + */ + extensionObjects: (extensionName: string): string => + `SELECT * FROM pg_catalog.pg_depend d + JOIN pg_catalog.pg_extension e ON d.refobjid = e.oid + JOIN pg_catalog.pg_class c ON d.objid = c.oid + WHERE e.extname = '${extensionName}' + AND d.deptype = 'e'`, + + /** + * Build foreign table info query + */ + foreignTableInfo: (schema: string, table: string): string => + `SELECT + c.column_name, + c.data_type, + c.is_nullable, + c.column_default, + fs.srvname as server_name, + fto.ftoptions as options +FROM information_schema.columns c +JOIN pg_class pc ON pc.relname = c.table_name +JOIN pg_foreign_table ft ON ft.ftrelid = pc.oid +JOIN pg_foreign_server fs ON fs.oid = ft.ftserver +LEFT JOIN pg_foreign_table_options fto ON fto.ftrelid = ft.ftrelid +WHERE c.table_schema = '${schema}' +AND c.table_name = '${table}' +ORDER BY c.ordinal_position`, + + /** + * Build foreign table definition query + */ + foreignTableDefinition: (schema: string, table: string): string => + `SELECT + c.relname as table_name, + fs.srvname as server_name, + array_agg( + format('%I %s%s', + a.attname, + format_type(a.atttypid, a.atttypmod), + CASE WHEN a.attnotnull THEN ' NOT NULL' ELSE '' END + ) ORDER BY a.attnum + ) as columns, + ftoptions as options +FROM pg_class c +JOIN pg_foreign_table ft ON c.oid = ft.ftrelid +JOIN pg_foreign_server fs ON fs.oid = ft.ftserver +JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 +LEFT JOIN pg_foreign_table_options fto ON fto.ftrelid = ft.ftrelid +JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE c.relname = '${table}' +AND n.nspname = '${schema}' +GROUP BY c.relname, fs.srvname, ftoptions`, + + /** + * Build materialized view info query + */ + matViewInfo: (schema: string, view: string): string => + `SELECT pg_get_viewdef('${schema}.${view}'::regclass, true) as definition, + schemaname, + matviewname, + matviewowner, + tablespace, + hasindexes, + ispopulated, + pg_size_pretty(pg_total_relation_size(format('%I.%I', schemaname, matviewname))) as size +FROM pg_matviews +WHERE schemaname = '${schema}' AND matviewname = '${view}'`, + + /** + * Build materialized view definition query + */ + matViewDefinition: (schema: string, view: string): string => + `SELECT pg_get_viewdef('${schema}.${view}'::regclass, true) as definition +FROM pg_matviews +WHERE schemaname = '${schema}' AND matviewname = '${view}'`, + + /** + * Build materialized view stats query + */ + matViewStats: (schema: string, view: string): string => + `SELECT + n_live_tup as live_tuples, + n_dead_tup as dead_tuples, + last_vacuum, + last_autovacuum, + last_analyze, + last_autoanalyze +FROM pg_stat_user_tables +WHERE schemaname = '${schema}' AND relname = '${view}'`, + + /** + * Build object dependencies query + */ + objectDependencies: (schema: string, name: string): string => + `SELECT DISTINCT + dependent_ns.nspname as schema, + dependent_view.relname as name, + dependent_view.relkind as kind +FROM pg_depend +JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid +JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid +JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace +WHERE pg_depend.refobjid = '${schema}.${name}'::regclass +AND dependent_view.relname != '${name}' +ORDER BY schema, name`, + + /** + * Build object references query + */ + objectReferences: (schema: string, name: string): string => + `SELECT DISTINCT + ref_nsp.nspname as schema, + ref_class.relname as name, + ref_class.relkind as kind +FROM pg_depend dep +JOIN pg_rewrite rew ON dep.objid = rew.oid +JOIN pg_class ref_class ON dep.refobjid = ref_class.oid +JOIN pg_namespace ref_nsp ON ref_nsp.oid = ref_class.relnamespace +WHERE rew.ev_class = '${schema}.${name}'::regclass +AND ref_class.relname != '${name}' +AND ref_class.relkind IN ('r', 'v', 'm') +ORDER BY schema, name`, + + /** + * Build database statistics query + */ + databaseStats: (): string => + `SELECT + d.datname as "Database", + pg_size_pretty(pg_database_size(d.datname)) as "Size", + u.usename as "Owner", + (SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()) as "Active Connections", + (SELECT count(*) FROM pg_namespace WHERE nspname NOT IN ('pg_catalog', 'information_schema')) as "Schemas", + (SELECT count(*) FROM pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema')) as "Tables", + (SELECT count(*) FROM pg_roles) as "Roles" +FROM pg_database d +JOIN pg_user u ON d.datdba = u.usesysid +WHERE d.datname = current_database()`, + + /** + * Build database schema sizes query + */ + databaseSchemaSizes: (): string => + `SELECT + pg_tables.schemaname as schema_name, + pg_total_relation_size(pg_tables.schemaname || '.' || tablename) as table_size +FROM pg_tables +WHERE pg_tables.schemaname NOT IN ('pg_catalog', 'information_schema')`, + + /** + * Build database schema size summary query + */ + databaseSchemaSizeSummary: (): string => + `SELECT schema_name, + pg_size_pretty(sum(table_size)::bigint) as "Size", + count(table_name) as "Tables" +FROM ( + SELECT pg_tables.schemaname as schema_name, + tablename as table_name, + pg_total_relation_size(pg_tables.schemaname || '.' || tablename) as table_size + FROM pg_tables +) t +GROUP BY schema_name +ORDER BY sum(table_size) DESC`, + + /** + * Build database maintenance stats query + */ + databaseMaintenanceStats: (): string => + `SELECT + schemaname || '.' || relname as "Table", + n_dead_tup as "Dead Tuples", + n_live_tup as "Live Tuples", + last_vacuum as "Last Vacuum", + last_autovacuum as "Last Auto Vacuum", + pg_size_pretty(pg_total_relation_size(schemaname || '.' || relname)) as "Total Size" +FROM pg_stat_user_tables +WHERE n_dead_tup > 0 +ORDER BY n_dead_tup DESC +LIMIT 20`, + + /** + * Build database configuration query + */ + databaseConfiguration: (): string => + `SELECT + name as "Setting", + setting as "Value", + unit as "Unit", + category as "Category", + short_desc as "Description" +FROM pg_settings +ORDER BY category, name`, + + /** + * Build database memory settings query + */ + databaseMemorySettings: (): string => + `SELECT + name as "Setting", + setting as "Value", + unit as "Unit", + short_desc as "Description" +FROM pg_settings +WHERE category LIKE '%Memory%' OR name LIKE '%memory%' OR name LIKE '%buffer%' +ORDER BY name`, + + /** + * Build database connection settings query + */ + databaseConnectionSettings: (): string => + `SELECT + name as "Setting", + setting as "Value", + unit as "Unit", + short_desc as "Description" +FROM pg_settings +WHERE category LIKE '%Connection%' OR name LIKE '%connection%' +ORDER BY name`, + + /** + * Build database active connections query + */ + databaseActiveConnections: (): string => + `SELECT pid as "Process ID", + usename as "User", + datname as "Database", + client_addr as "Client Address", + application_name as "Application", + state as "State", + query as "Last Query", + backend_start as "Connected Since" +FROM pg_stat_activity +WHERE datname = current_database() +ORDER BY backend_start`, + + /** + * Build database extensions query + */ + databaseExtensions: (): string => + `SELECT name as "Extension", + default_version as "Default Version", + installed_version as "Installed Version", + comment as "Description" +FROM pg_available_extensions +WHERE installed_version IS NOT NULL +ORDER BY name`, + + /** + * Build database roles query + */ + databaseRoles: (): string => + `SELECT + r.rolname as "Role", + r.rolsuper as "Superuser", + r.rolcreatedb as "Create DB", + r.rolcreaterole as "Create Role", + r.rolcanlogin as "Can Login", + r.rolconnlimit as "Connection Limit", + r.rolvaliduntil as "Valid Until" +FROM pg_roles r +ORDER BY r.rolname`, + + /** + * Build terminate connections query + */ + databaseTerminateConnections: (databaseName?: string): string => { + const dbFilter = databaseName ? `WHERE datname = '${databaseName}'` : `WHERE datname = current_database()`; + return `SELECT format( + 'SELECT pg_terminate_backend(%s) /* %s %s %s */;', + pid, + usename, + application_name, + query +) +FROM pg_stat_activity +${dbFilter} +AND pid <> pg_backend_pid();`; + }, + + /** + * Build terminate connections by PID query + */ + terminateConnectionsByPid: (databaseName: string): string => + `SELECT pg_terminate_backend(pid) +FROM pg_stat_activity +WHERE datname = '${databaseName}' + AND pid <> pg_backend_pid();` +}; + +/** + * Common maintenance operations + */ +export const MaintenanceTemplates = { + vacuum: (schema: string, table: string): string => + `-- Vacuum table\nVACUUM (VERBOSE, ANALYZE) ${schema}.${table};`, + + analyze: (schema: string, table: string): string => + `-- Analyze table\nANALYZE VERBOSE ${schema}.${table};`, + + reindex: (schema: string, table: string): string => + `-- Reindex table\nREINDEX TABLE ${schema}.${table};`, + + vacuumFull: (schema: string, table: string): string => + `-- Vacuum full (locks table)\nVACUUM FULL ${schema}.${table};`, + + vacuumAnalyzeDatabase: (): string => + `-- Vacuum and update statistics (safe, non-blocking)\nVACUUM (VERBOSE, ANALYZE);`, + + reindexDatabase: (databaseName: string): string => + `-- Reindex entire database (locks tables during rebuild)\n-- REINDEX DATABASE "${databaseName}";` +}; diff --git a/src/commands/sql/index.ts b/src/commands/sql/index.ts index 31c30ba..9d7f6ba 100644 --- a/src/commands/sql/index.ts +++ b/src/commands/sql/index.ts @@ -15,3 +15,4 @@ export { TypeSQL } from './types'; export { ExtensionSQL } from './extensions'; export { MaterializedViewSQL } from './materializedViews'; export { ForeignTableSQL } from './foreignTables'; +export { SQL_TEMPLATES, QueryBuilder, MaintenanceTemplates } from './helper'; diff --git a/src/notebookProvider.ts b/src/notebookProvider.ts index c3906e0..ed81ab4 100644 --- a/src/notebookProvider.ts +++ b/src/notebookProvider.ts @@ -17,6 +17,8 @@ interface NotebookMetadata { interface Cell { value: string; + kind?: 'markdown' | 'sql'; + language?: 'markdown' | 'sql'; } export class PostgresNotebookProvider implements vscode.NotebookSerializer { @@ -34,13 +36,14 @@ export class PostgresNotebookProvider implements vscode.NotebookSerializer { metadata = data.metadata; } if (Array.isArray(data.cells)) { - cells = data.cells.map((cell: Cell) => - new vscode.NotebookCellData( - vscode.NotebookCellKind.Code, + cells = data.cells.map((cell: Cell) => { + const isMarkdown = cell.kind === 'markdown'; + return new vscode.NotebookCellData( + isMarkdown ? vscode.NotebookCellKind.Markup : vscode.NotebookCellKind.Code, cell.value, - 'sql' - ) - ); + isMarkdown ? 'markdown' : 'sql' + ); + }); } } catch { cells = [ diff --git a/src/providers/ChatViewProvider.ts b/src/providers/ChatViewProvider.ts index 825412d..9792f2e 100644 --- a/src/providers/ChatViewProvider.ts +++ b/src/providers/ChatViewProvider.ts @@ -8,10 +8,10 @@ * - webviewHtml: Provides the webview HTML template */ import * as vscode from 'vscode'; -import { - ChatMessage, - FileAttachment, - DbMention, +import { + ChatMessage, + FileAttachment, + DbMention, DbObject, DbObjectService, AiService, @@ -25,14 +25,14 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { private _view?: vscode.WebviewView; private _messages: ChatMessage[] = []; private _isProcessing = false; - + // Services private _dbObjectService: DbObjectService; private _aiService: AiService; private _sessionService: SessionService; constructor( - private readonly _extensionUri: vscode.Uri, + private readonly _extensionUri: vscode.Uri, context: vscode.ExtensionContext ) { this._dbObjectService = new DbObjectService(); @@ -60,7 +60,12 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { localResourceRoots: [this._extensionUri] }; - webviewView.webview.html = getWebviewHtml(webviewView.webview); + // Send URI for marked.js and highlight.js + const markedUri = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'resources', 'marked.min.js')); + const highlightJsUri = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'resources', 'highlight.min.js')); + const highlightCssUri = webviewView.webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'resources', 'highlight.css')); + + webviewView.webview.html = getWebviewHtml(webviewView.webview, markedUri, highlightJsUri, highlightCssUri); // Send initial history and model info setTimeout(() => { @@ -110,6 +115,9 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { case 'openAiSettings': vscode.commands.executeCommand('postgres-explorer.aiSettings'); break; + case 'openInNotebook': + await this._handleOpenInNotebook(data.code); + break; } }); } @@ -122,7 +130,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { } this._isProcessing = true; - + console.log('[ChatView] ========== HANDLING USER MESSAGE =========='); console.log('[ChatView] Message:', message); console.log('[ChatView] Attachments:', attachments?.length || 0); @@ -134,7 +142,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { // Build message with attachments let fullMessage = message; if (attachments && attachments.length > 0) { - const attachmentTexts = attachments.map(att => + const attachmentTexts = attachments.map(att => `\n\nπŸ“Ž **Attached File: ${att.name}** (${att.type})\n\`\`\`${att.type}\n${att.content}\n\`\`\`` ).join(''); fullMessage = message + attachmentTexts; @@ -145,7 +153,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { if (mentions && mentions.length > 0) { console.log('[ChatView] Processing mentions for schema context...'); let schemaContext = '\n\n=== DATABASE SCHEMA CONTEXT (Use this information to answer the question) ===\n'; - + for (const mention of mentions) { console.log('[ChatView] Fetching schema for:', mention.schema + '.' + mention.name, 'type:', mention.type, 'connectionId:', mention.connectionId); const obj: DbObject = { @@ -157,7 +165,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { connectionName: '', breadcrumb: mention.breadcrumb }; - + try { const schemaInfo = await this._dbObjectService.getObjectSchema(obj); mention.schemaInfo = schemaInfo; @@ -169,22 +177,22 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { } catch (e) { const errorMsg = e instanceof Error ? e.message : String(e); console.error('[ChatView] Failed to get schema for mention:', mention.name, e); - + // Notify user about the error this._view?.webview.postMessage({ type: 'schemaError', object: `${mention.schema}.${mention.name}`, error: errorMsg }); - + // Still add a note in context so AI knows there was an issue schemaContext += `\n### ${mention.type.toUpperCase()}: ${mention.schema}.${mention.name}\n`; schemaContext += `[Schema could not be retrieved: ${errorMsg}]\n`; } } - + schemaContext += '\n=== END DATABASE SCHEMA CONTEXT ===\n\n'; - + // Prepend schema context to the message so AI sees it first aiMessage = schemaContext + fullMessage; console.log('[ChatView] AI message with schema context length:', aiMessage.length); @@ -222,21 +230,21 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { console.log('[ChatView] Calling direct API:', provider); response = await this._aiService.callDirectApi(provider, aiMessage, config); } - + console.log('[ChatView] AI response received, length:', response.length); - + // Sanitize response - remove any HTML-like patterns that shouldn't be there // This prevents the model from learning bad patterns from previous responses response = this._sanitizeResponse(response); this._messages.push({ role: 'assistant', content: response }); - + await this._saveCurrentSession(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); - this._messages.push({ - role: 'assistant', - content: `❌ Error: ${errorMessage}\n\nPlease check your AI provider settings in the extension configuration.` + this._messages.push({ + role: 'assistant', + content: `❌ Error: ${errorMessage}\n\nPlease check your AI provider settings in the extension configuration.` }); } finally { this._setTypingIndicator(false); @@ -250,19 +258,15 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { // Remove patterns like: sql-keyword">, sql-string">, sql-function">, sql-number">, function"> // These are CSS class artifacts that sometimes leak into AI responses let cleaned = response; - + // Remove CSS class-like patterns followed by "> cleaned = cleaned.replace(/\b(sql-keyword|sql-string|sql-function|sql-number|sql-type|sql-comment|sql-operator|sql-special|function)"\s*>/gi, ''); - - // Remove any remaining HTML-like tags that shouldn't be in markdown - cleaned = cleaned.replace(/]*>/gi, ''); - cleaned = cleaned.replace(/<\/span>/gi, ''); - + // Log if we found and cleaned anything if (cleaned !== response) { console.log('[ChatView] Sanitized AI response - removed HTML artifacts'); } - + return cleaned; } @@ -274,9 +278,9 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { if (this._dbObjectService.getCache().length === 0) { await this._dbObjectService.fetchDbObjects(); } - + const filtered = this._dbObjectService.searchObjects(query); - + this._view?.webview.postMessage({ type: 'dbObjectsResult', objects: filtered @@ -338,9 +342,9 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { const fileContent = await vscode.workspace.fs.readFile(fileUri[0]); const content = new TextDecoder().decode(fileContent); const fileName = fileUri[0].path.split('/').pop() || 'file'; - + const maxSize = 50000; - const truncatedContent = content.length > maxSize + const truncatedContent = content.length > maxSize ? content.substring(0, maxSize) + '\n... (truncated)' : content; @@ -370,14 +374,58 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { return typeMap[ext] || 'text'; } + // ==================== Notebook Integration ==================== + + private async _handleOpenInNotebook(code: string): Promise { + try { + const activeNotebook = vscode.window.activeNotebookEditor; + + if (activeNotebook && activeNotebook.notebook.notebookType === 'postgres-notebook') { + // Insert new SQL cell at the end + const edit = new vscode.WorkspaceEdit(); + const cellData = new vscode.NotebookCellData( + vscode.NotebookCellKind.Code, + code, + 'sql' + ); + const notebookEdit = vscode.NotebookEdit.insertCells( + activeNotebook.notebook.cellCount, + [cellData] + ); + edit.set(activeNotebook.notebook.uri, [notebookEdit]); + await vscode.workspace.applyEdit(edit); + + // Send success back to webview + this._view?.webview.postMessage({ + type: 'notebookResult', + success: true + }); + } else { + // No active notebook - send error back to webview + this._view?.webview.postMessage({ + type: 'notebookResult', + success: false, + error: 'Open notebook first' + }); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + this._view?.webview.postMessage({ + type: 'notebookResult', + success: false, + error: errorMessage + }); + } + } + // ==================== Session Management ==================== private async _saveCurrentSession(): Promise { const config = vscode.workspace.getConfiguration('postgresExplorer'); const provider = config.get('aiProvider') || 'vscode-lm'; - + await this._sessionService.saveSession( - this._messages, + this._messages, (msg) => this._aiService.generateTitle(msg, provider) ); this._sendHistoryToWebview(); @@ -395,12 +443,12 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { console.log('[ChatView] _deleteSession called with:', sessionId); const wasCurrentSession = await this._sessionService.deleteSession(sessionId); console.log('[ChatView] Session deleted, wasCurrentSession:', wasCurrentSession); - + if (wasCurrentSession) { this._messages = []; this._updateChatHistory(); } - + console.log('[ChatView] Sending updated history to webview...'); this._sendHistoryToWebview(); } @@ -439,7 +487,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider { const config = vscode.workspace.getConfiguration('postgresExplorer'); const provider = config.get('aiProvider') || 'vscode-lm'; const modelInfo = await this._aiService.getModelInfo(provider, config); - + this._view.webview.postMessage({ type: 'updateModelInfo', modelName: modelInfo diff --git a/src/providers/chat/AiService.ts b/src/providers/chat/AiService.ts index abe0764..14115d5 100644 --- a/src/providers/chat/AiService.ts +++ b/src/providers/chat/AiService.ts @@ -100,22 +100,22 @@ IMPORTANT: At the end of each response, provide 2-4 numbered follow-up questions Make these questions relevant to the topic discussed and progressively more advanced.`; } - async callVsCodeLm(userMessage: string, config: vscode.WorkspaceConfiguration): Promise { + async callVsCodeLm(userMessage: string, config: vscode.WorkspaceConfiguration, customSystemPrompt?: string): Promise { const configuredModel = config.get('aiModel'); let models: vscode.LanguageModelChat[]; - + if (configuredModel) { // Extract base name if format is "name (family)" const baseName = configuredModel.replace(/\s*\(.*\)$/, '').trim(); - + // Try to find the specific model by name/id/family const allModels = await vscode.lm.selectChatModels({}); - const matchingModels = allModels.filter(m => - m.id === baseName || - m.name === baseName || + const matchingModels = allModels.filter(m => + m.id === baseName || + m.name === baseName || m.family === baseName || - m.id === configuredModel || - m.name === configuredModel || + m.id === configuredModel || + m.name === configuredModel || m.family === configuredModel ); models = matchingModels.length > 0 ? matchingModels : allModels; @@ -132,29 +132,26 @@ Make these questions relevant to the topic discussed and progressively more adva throw new Error('No AI models available via VS Code API. Please ensure GitHub Copilot Chat is installed or switch provider.'); } - const systemPrompt = this.buildSystemPrompt(); - const messages = [ - vscode.LanguageModelChatMessage.User(systemPrompt), - ...this._messages.slice(-10).map(msg => - msg.role === 'user' + const systemPrompt = customSystemPrompt !== undefined ? customSystemPrompt : this.buildSystemPrompt(); + + const messages = []; + if (systemPrompt) { + messages.push(vscode.LanguageModelChatMessage.User(systemPrompt)); + } + + messages.push( + ...this._messages.slice(-10).map(msg => + msg.role === 'user' ? vscode.LanguageModelChatMessage.User(this._sanitizeContent(msg.content)) : vscode.LanguageModelChatMessage.Assistant(this._sanitizeContent(msg.content)) - ), - vscode.LanguageModelChatMessage.User(userMessage) - ]; + ) + ); + messages.push(vscode.LanguageModelChatMessage.User(userMessage)); // Debug: Log all messages being sent to model console.log('[AiService] ========== MESSAGES SENT TO MODEL =========='); console.log('[AiService] System prompt length:', systemPrompt.length); console.log('[AiService] Conversation history messages:', this._messages.length); - for (let i = 0; i < messages.length; i++) { - const msg = messages[i]; - const role = i === 0 ? 'SYSTEM' : (msg.role === vscode.LanguageModelChatMessageRole.User ? 'USER' : 'ASSISTANT'); - const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content); - console.log(`[AiService] Message ${i} (${role}):`, content.substring(0, 500) + (content.length > 500 ? '...' : '')); - } - console.log('[AiService] Current user message:', userMessage); - console.log('[AiService] ========== END MESSAGES =========='); const chatRequest = await model.sendRequest(messages, {}, new vscode.CancellationTokenSource().token); let responseText = ''; @@ -163,11 +160,6 @@ Make these questions relevant to the topic discussed and progressively more adva responseText += fragment; } - // Debug: Log raw response from model - console.log('[AiService] ========== RAW RESPONSE FROM MODEL =========='); - console.log(responseText); - console.log('[AiService] ========== END RAW RESPONSE =========='); - return responseText; } @@ -176,12 +168,10 @@ Make these questions relevant to the topic discussed and progressively more adva let cleaned = content; // Remove CSS class-like patterns that may have leaked into history cleaned = cleaned.replace(/\b(sql-keyword|sql-string|sql-function|sql-number|sql-type|sql-comment|sql-operator|sql-special|function)"\s*>/gi, ''); - cleaned = cleaned.replace(/]*>/gi, ''); - cleaned = cleaned.replace(/<\/span>/gi, ''); return cleaned; } - async callDirectApi(provider: string, userMessage: string, config: vscode.WorkspaceConfiguration): Promise { + async callDirectApi(provider: string, userMessage: string, config: vscode.WorkspaceConfiguration, customSystemPrompt?: string): Promise { const apiKey = config.get('aiApiKey'); if (!apiKey) { throw new Error(`API Key is required for ${provider} provider. Please configure postgresExplorer.aiApiKey.`); @@ -195,8 +185,8 @@ Make these questions relevant to the topic discussed and progressively more adva }; let body: any = {}; - const systemPrompt = this.buildSystemPrompt(); - + const systemPrompt = customSystemPrompt !== undefined ? customSystemPrompt : this.buildSystemPrompt(); + // Sanitize conversation history to remove any HTML artifacts const conversationHistory = this._messages.slice(-10).map(msg => ({ role: msg.role, @@ -205,14 +195,18 @@ Make these questions relevant to the topic discussed and progressively more adva if (provider === 'openai') { endpoint = 'https://api.openai.com/v1/chat/completions'; - model = model || 'gpt-4'; + model = model || 'gpt-4o'; + + const messages: any[] = []; + if (systemPrompt) { + messages.push({ role: 'system', content: systemPrompt }); + } + messages.push(...conversationHistory); + messages.push({ role: 'user', content: userMessage }); + body = { model: model, - messages: [ - { role: 'system', content: systemPrompt }, - ...conversationHistory, - { role: 'user', content: userMessage } - ], + messages: messages, temperature: 0.7 }; } else if (provider === 'anthropic') { @@ -231,34 +225,38 @@ Make these questions relevant to the topic discussed and progressively more adva max_tokens: 4096 }; } else if (provider === 'gemini') { - model = model || 'gemini-pro'; + model = model || 'gemini-1.5-flash'; endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`; headers['X-goog-api-key'] = apiKey; delete headers['Authorization']; - - const contents = [ - { role: 'user', parts: [{ text: systemPrompt }] }, - ...conversationHistory.map(msg => ({ - role: msg.role === 'assistant' ? 'model' : 'user', - parts: [{ text: msg.content }] - })), - { role: 'user', parts: [{ text: userMessage }] } - ]; - - body = { contents }; + + body = { + systemInstruction: systemPrompt ? { parts: [{ text: systemPrompt }] } : undefined, + contents: [ + ...conversationHistory.map(msg => ({ + role: msg.role === 'assistant' ? 'model' : 'user', + parts: [{ text: msg.content }] + })), + { role: 'user', parts: [{ text: userMessage }] } + ] + }; } else if (provider === 'custom') { endpoint = config.get('aiEndpoint') || ''; if (!endpoint) { throw new Error('Endpoint is required for custom provider'); } model = model || 'gpt-3.5-turbo'; + + const messages: any[] = []; + if (systemPrompt) { + messages.push({ role: 'system', content: systemPrompt }); + } + messages.push(...conversationHistory); + messages.push({ role: 'user', content: userMessage }); + body = { model: model, - messages: [ - { role: 'system', content: systemPrompt }, - ...conversationHistory, - { role: 'user', content: userMessage } - ] + messages: messages }; } else { throw new Error(`Unsupported provider: ${provider}`); @@ -288,7 +286,7 @@ Make these questions relevant to the topic discussed and progressively more adva res.on('end', () => { try { const response = JSON.parse(data); - + if (res.statusCode !== 200) { reject(new Error(response.error?.message || `API request failed with status ${res.statusCode}`)); return; @@ -302,10 +300,15 @@ Make these questions relevant to the topic discussed and progressively more adva } else { content = response.choices?.[0]?.message?.content || ''; } - + + if (!content && provider === 'custom') { + content = JSON.stringify(response); // Fallback + } + resolve(content); } catch (e) { - reject(new Error('Failed to parse API response')); + // If response is not JSON, we might want to log it + reject(new Error(`Failed to parse API response: ${e instanceof Error ? e.message : String(e)}`)); } }); }); @@ -331,7 +334,7 @@ Make these questions relevant to the topic discussed and progressively more adva return title.trim().substring(0, 50); } } - + // Fallback to simple extraction const title = firstMessage.substring(0, 40).replace(/\n/g, ' ').trim(); return title.length === 40 ? title + '...' : title; @@ -344,12 +347,12 @@ Make these questions relevant to the topic discussed and progressively more adva async getModelInfo(provider: string, config: vscode.WorkspaceConfiguration): Promise { try { const configuredModel = config.get('aiModel'); - + if (provider === 'vscode-lm') { if (configuredModel) { const baseName = configuredModel.replace(/\s*\(.*\)$/, '').trim(); - const allModels = await vscode.lm.selectChatModels({}); - const matchingModels = allModels.filter(m => + const allModels = await this._selectChatModelsWithTimeout({}); + const matchingModels = allModels.filter((m: vscode.LanguageModelChat) => m.id === baseName || m.name === baseName || m.family === baseName || m.id === configuredModel || m.name === configuredModel || m.family === configuredModel ); @@ -357,12 +360,12 @@ Make these questions relevant to the topic discussed and progressively more adva return matchingModels[0].name || matchingModels[0].id; } } - const models = await vscode.lm.selectChatModels({ family: 'gpt-4o' }); + const models = await this._selectChatModelsWithTimeout({ family: 'gpt-4o' }); if (models.length > 0) { return models[0].name || models[0].id; } - const anyModels = await vscode.lm.selectChatModels({}); - return anyModels.length > 0 ? (anyModels[0].name || anyModels[0].id) : 'Unknown'; + const anyModels = await this._selectChatModelsWithTimeout({}); + return anyModels.length > 0 ? (anyModels[0].name || anyModels[0].id) : 'VS Code LM (No Models)'; } else { return configuredModel || this._getDefaultModel(provider); } @@ -373,11 +376,29 @@ Make these questions relevant to the topic discussed and progressively more adva private _getDefaultModel(provider: string): string { switch (provider) { - case 'openai': return 'gpt-4'; + case 'openai': return 'gpt-4o'; case 'anthropic': return 'claude-3-5-sonnet-20241022'; - case 'gemini': return 'gemini-pro'; + case 'gemini': return 'gemini-1.5-flash'; case 'custom': return 'custom-model'; default: return 'Unknown'; } } + + private async _selectChatModelsWithTimeout(selector: vscode.LanguageModelChatSelector): Promise { + return new Promise((resolve) => { + const timeout = setTimeout(() => { + console.warn('[AiService] vscode.lm.selectChatModels timed out after 2000ms'); + resolve([]); + }, 2000); + + vscode.lm.selectChatModels(selector).then((models) => { + clearTimeout(timeout); + resolve(models); + }, (error) => { + clearTimeout(timeout); + console.error('[AiService] vscode.lm.selectChatModels failed:', error); + resolve([]); + }); + }); + } } diff --git a/src/providers/chat/webviewHtml.ts b/src/providers/chat/webviewHtml.ts index 24fede9..308bb84 100644 --- a/src/providers/chat/webviewHtml.ts +++ b/src/providers/chat/webviewHtml.ts @@ -3,13 +3,19 @@ */ import * as vscode from 'vscode'; -export function getWebviewHtml(webview: vscode.Webview): string { +export function getWebviewHtml(webview: vscode.Webview, markedUri: vscode.Uri, highlightJsUri: vscode.Uri, highlightCssUri: vscode.Uri): string { + const cspSource = webview.cspSource; + return ` + PostgreSQL Chat + + +