From 88653deb4b839a53be31aa06e1cf10cfe2c043bf Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Tue, 18 Jun 2024 09:21:53 +0200
Subject: [PATCH 1/7] feat(vscode-pv-handlebars-language-server): add
 handlebars diagnostics

vscode plugin will highlight any parse errors in the handlebars file or its yaml front matter
---
 .../package-lock.json                         | 3561 +++++++++++------
 .../package.json                              |   12 +-
 .../server/package-lock.json                  |  149 +-
 .../server/package.json                       |    5 +-
 .../server/src/SettingsService.ts             |    1 +
 .../server/src/diagnosticProvider.ts          |  162 +
 .../server/src/server.ts                      |   53 +-
 7 files changed, 2627 insertions(+), 1316 deletions(-)
 create mode 100644 packages/vscode-pv-handlebars-language-server/server/src/diagnosticProvider.ts

diff --git a/packages/vscode-pv-handlebars-language-server/package-lock.json b/packages/vscode-pv-handlebars-language-server/package-lock.json
index b049c2cd..fb479082 100644
--- a/packages/vscode-pv-handlebars-language-server/package-lock.json
+++ b/packages/vscode-pv-handlebars-language-server/package-lock.json
@@ -1,1244 +1,2321 @@
 {
-	"name": "vscode-pv-handlebars-language-server",
-	"version": "0.8.0",
-	"lockfileVersion": 2,
-	"requires": true,
-	"packages": {
-		"": {
-			"name": "vscode-pv-handlebars-language-server",
-			"version": "0.7.3",
-			"license": "Apache-2.0",
-			"devDependencies": {
-				"@types/node": "^12.12.0",
-				"typescript": "^4.2.3",
-				"vsce": "^1.87.0"
-			},
-			"engines": {
-				"vscode": "^1.43.0"
-			}
-		},
-		"node_modules/@types/node": {
-			"version": "12.20.7",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.7.tgz",
-			"integrity": "sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA==",
-			"dev": true
-		},
-		"node_modules/ansi-styles": {
-			"version": "3.2.1",
-			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-			"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-			"dev": true,
-			"dependencies": {
-				"color-convert": "^1.9.0"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/argparse": {
-			"version": "1.0.10",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-			"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-			"dev": true,
-			"dependencies": {
-				"sprintf-js": "~1.0.2"
-			}
-		},
-		"node_modules/azure-devops-node-api": {
-			"version": "7.2.0",
-			"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-7.2.0.tgz",
-			"integrity": "sha512-pMfGJ6gAQ7LRKTHgiRF+8iaUUeGAI0c8puLaqHLc7B8AR7W6GJLozK9RFeUHFjEGybC9/EB3r67WPd7e46zQ8w==",
-			"dev": true,
-			"dependencies": {
-				"os": "0.1.1",
-				"tunnel": "0.0.4",
-				"typed-rest-client": "1.2.0",
-				"underscore": "1.8.3"
-			}
-		},
-		"node_modules/balanced-match": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-			"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-			"dev": true
-		},
-		"node_modules/boolbase": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-			"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
-			"dev": true
-		},
-		"node_modules/brace-expansion": {
-			"version": "1.1.11",
-			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-			"dev": true,
-			"dependencies": {
-				"balanced-match": "^1.0.0",
-				"concat-map": "0.0.1"
-			}
-		},
-		"node_modules/buffer-crc32": {
-			"version": "0.2.13",
-			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
-			"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
-			"dev": true,
-			"engines": {
-				"node": "*"
-			}
-		},
-		"node_modules/chalk": {
-			"version": "2.4.2",
-			"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-			"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-			"dev": true,
-			"dependencies": {
-				"ansi-styles": "^3.2.1",
-				"escape-string-regexp": "^1.0.5",
-				"supports-color": "^5.3.0"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/cheerio": {
-			"version": "1.0.0-rc.5",
-			"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz",
-			"integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==",
-			"dev": true,
-			"dependencies": {
-				"cheerio-select-tmp": "^0.1.0",
-				"dom-serializer": "~1.2.0",
-				"domhandler": "^4.0.0",
-				"entities": "~2.1.0",
-				"htmlparser2": "^6.0.0",
-				"parse5": "^6.0.0",
-				"parse5-htmlparser2-tree-adapter": "^6.0.0"
-			},
-			"engines": {
-				"node": ">= 0.12"
-			}
-		},
-		"node_modules/cheerio-select-tmp": {
-			"version": "0.1.1",
-			"resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz",
-			"integrity": "sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==",
-			"deprecated": "Use cheerio-select instead",
-			"dev": true,
-			"dependencies": {
-				"css-select": "^3.1.2",
-				"css-what": "^4.0.0",
-				"domelementtype": "^2.1.0",
-				"domhandler": "^4.0.0",
-				"domutils": "^2.4.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/fb55"
-			}
-		},
-		"node_modules/color-convert": {
-			"version": "1.9.3",
-			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-			"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-			"dev": true,
-			"dependencies": {
-				"color-name": "1.1.3"
-			}
-		},
-		"node_modules/color-name": {
-			"version": "1.1.3",
-			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-			"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-			"dev": true
-		},
-		"node_modules/commander": {
-			"version": "6.2.1",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
-			"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
-			"dev": true,
-			"engines": {
-				"node": ">= 6"
-			}
-		},
-		"node_modules/concat-map": {
-			"version": "0.0.1",
-			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-			"dev": true
-		},
-		"node_modules/css-select": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz",
-			"integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==",
-			"dev": true,
-			"dependencies": {
-				"boolbase": "^1.0.0",
-				"css-what": "^4.0.0",
-				"domhandler": "^4.0.0",
-				"domutils": "^2.4.3",
-				"nth-check": "^2.0.0"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/fb55"
-			}
-		},
-		"node_modules/css-what": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz",
-			"integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==",
-			"dev": true,
-			"engines": {
-				"node": ">= 6"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/fb55"
-			}
-		},
-		"node_modules/denodeify": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
-			"integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=",
-			"dev": true
-		},
-		"node_modules/dom-serializer": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
-			"integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
-			"dev": true,
-			"dependencies": {
-				"domelementtype": "^2.0.1",
-				"domhandler": "^4.0.0",
-				"entities": "^2.0.0"
-			},
-			"funding": {
-				"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
-			}
-		},
-		"node_modules/domelementtype": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
-			"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
-			"dev": true,
-			"funding": [
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/fb55"
-				}
-			]
-		},
-		"node_modules/domhandler": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.1.0.tgz",
-			"integrity": "sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==",
-			"dev": true,
-			"dependencies": {
-				"domelementtype": "^2.2.0"
-			},
-			"engines": {
-				"node": ">= 4"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/domhandler?sponsor=1"
-			}
-		},
-		"node_modules/domutils": {
-			"version": "2.5.1",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.1.tgz",
-			"integrity": "sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==",
-			"dev": true,
-			"dependencies": {
-				"dom-serializer": "^1.0.1",
-				"domelementtype": "^2.2.0",
-				"domhandler": "^4.1.0"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/domutils?sponsor=1"
-			}
-		},
-		"node_modules/entities": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
-			"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
-			"dev": true,
-			"funding": {
-				"url": "https://github.com/fb55/entities?sponsor=1"
-			}
-		},
-		"node_modules/escape-string-regexp": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.8.0"
-			}
-		},
-		"node_modules/fd-slicer": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
-			"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
-			"dev": true,
-			"dependencies": {
-				"pend": "~1.2.0"
-			}
-		},
-		"node_modules/fs.realpath": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-			"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-			"dev": true
-		},
-		"node_modules/glob": {
-			"version": "7.1.6",
-			"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-			"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-			"dev": true,
-			"dependencies": {
-				"fs.realpath": "^1.0.0",
-				"inflight": "^1.0.4",
-				"inherits": "2",
-				"minimatch": "^3.0.4",
-				"once": "^1.3.0",
-				"path-is-absolute": "^1.0.0"
-			},
-			"engines": {
-				"node": "*"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/has-flag": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-			"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-			"dev": true,
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/htmlparser2": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.1.tgz",
-			"integrity": "sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==",
-			"dev": true,
-			"funding": [
-				"https://github.com/fb55/htmlparser2?sponsor=1",
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/fb55"
-				}
-			],
-			"dependencies": {
-				"domelementtype": "^2.0.1",
-				"domhandler": "^4.0.0",
-				"domutils": "^2.4.4",
-				"entities": "^2.0.0"
-			}
-		},
-		"node_modules/inflight": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-			"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-			"dev": true,
-			"dependencies": {
-				"once": "^1.3.0",
-				"wrappy": "1"
-			}
-		},
-		"node_modules/inherits": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-			"dev": true
-		},
-		"node_modules/leven": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
-			"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
-			"dev": true,
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/linkify-it": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
-			"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
-			"dev": true,
-			"dependencies": {
-				"uc.micro": "^1.0.1"
-			}
-		},
-		"node_modules/lodash": {
-			"version": "4.17.21",
-			"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-			"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-			"dev": true
-		},
-		"node_modules/markdown-it": {
-			"version": "10.0.0",
-			"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
-			"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
-			"dev": true,
-			"dependencies": {
-				"argparse": "^1.0.7",
-				"entities": "~2.0.0",
-				"linkify-it": "^2.0.0",
-				"mdurl": "^1.0.1",
-				"uc.micro": "^1.0.5"
-			},
-			"bin": {
-				"markdown-it": "bin/markdown-it.js"
-			}
-		},
-		"node_modules/markdown-it/node_modules/entities": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
-			"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
-			"dev": true
-		},
-		"node_modules/mdurl": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
-			"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
-			"dev": true
-		},
-		"node_modules/mime": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-			"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-			"dev": true,
-			"bin": {
-				"mime": "cli.js"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/minimatch": {
-			"version": "3.0.4",
-			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-			"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-			"dev": true,
-			"dependencies": {
-				"brace-expansion": "^1.1.7"
-			},
-			"engines": {
-				"node": "*"
-			}
-		},
-		"node_modules/mute-stream": {
-			"version": "0.0.8",
-			"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-			"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
-			"dev": true
-		},
-		"node_modules/nth-check": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
-			"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
-			"dev": true,
-			"dependencies": {
-				"boolbase": "^1.0.0"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/nth-check?sponsor=1"
-			}
-		},
-		"node_modules/once": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-			"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-			"dev": true,
-			"dependencies": {
-				"wrappy": "1"
-			}
-		},
-		"node_modules/os": {
-			"version": "0.1.1",
-			"resolved": "https://registry.npmjs.org/os/-/os-0.1.1.tgz",
-			"integrity": "sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M=",
-			"dev": true
-		},
-		"node_modules/os-homedir": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-			"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/os-tmpdir": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-			"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/osenv": {
-			"version": "0.1.5",
-			"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-			"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-			"dev": true,
-			"dependencies": {
-				"os-homedir": "^1.0.0",
-				"os-tmpdir": "^1.0.0"
-			}
-		},
-		"node_modules/parse-semver": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
-			"integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
-			"dev": true,
-			"dependencies": {
-				"semver": "^5.1.0"
-			}
-		},
-		"node_modules/parse5": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
-			"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
-			"dev": true
-		},
-		"node_modules/parse5-htmlparser2-tree-adapter": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
-			"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
-			"dev": true,
-			"dependencies": {
-				"parse5": "^6.0.1"
-			}
-		},
-		"node_modules/path-is-absolute": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-			"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/pend": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
-			"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
-			"dev": true
-		},
-		"node_modules/read": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
-			"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
-			"dev": true,
-			"dependencies": {
-				"mute-stream": "~0.0.4"
-			},
-			"engines": {
-				"node": ">=0.8"
-			}
-		},
-		"node_modules/semver": {
-			"version": "5.7.1",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-			"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-			"dev": true,
-			"bin": {
-				"semver": "bin/semver"
-			}
-		},
-		"node_modules/sprintf-js": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-			"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-			"dev": true
-		},
-		"node_modules/supports-color": {
-			"version": "5.5.0",
-			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-			"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-			"dev": true,
-			"dependencies": {
-				"has-flag": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/tmp": {
-			"version": "0.0.29",
-			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
-			"integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=",
-			"dev": true,
-			"dependencies": {
-				"os-tmpdir": "~1.0.1"
-			},
-			"engines": {
-				"node": ">=0.4.0"
-			}
-		},
-		"node_modules/tunnel": {
-			"version": "0.0.4",
-			"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz",
-			"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
-			}
-		},
-		"node_modules/typed-rest-client": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.2.0.tgz",
-			"integrity": "sha512-FrUshzZ1yxH8YwGR29PWWnfksLEILbWJydU7zfIRkyH7kAEzB62uMAl2WY6EyolWpLpVHeJGgQm45/MaruaHpw==",
-			"dev": true,
-			"dependencies": {
-				"tunnel": "0.0.4",
-				"underscore": "1.8.3"
-			}
-		},
-		"node_modules/typescript": {
-			"version": "4.2.3",
-			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
-			"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
-			"dev": true,
-			"bin": {
-				"tsc": "bin/tsc",
-				"tsserver": "bin/tsserver"
-			},
-			"engines": {
-				"node": ">=4.2.0"
-			}
-		},
-		"node_modules/uc.micro": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
-			"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
-			"dev": true
-		},
-		"node_modules/underscore": {
-			"version": "1.8.3",
-			"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
-			"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
-			"dev": true
-		},
-		"node_modules/url-join": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
-			"integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=",
-			"dev": true
-		},
-		"node_modules/vsce": {
-			"version": "1.87.1",
-			"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.87.1.tgz",
-			"integrity": "sha512-3tSUWZl9AmhZrqy/UVUpdPODSzBiCGjIr/AMSSgF2PuFLSdrh+6kiOr2Ath7bpQEXOxf55hNgz3qdO5MuEJmww==",
-			"dev": true,
-			"dependencies": {
-				"azure-devops-node-api": "^7.2.0",
-				"chalk": "^2.4.2",
-				"cheerio": "^1.0.0-rc.1",
-				"commander": "^6.1.0",
-				"denodeify": "^1.2.1",
-				"glob": "^7.0.6",
-				"leven": "^3.1.0",
-				"lodash": "^4.17.15",
-				"markdown-it": "^10.0.0",
-				"mime": "^1.3.4",
-				"minimatch": "^3.0.3",
-				"osenv": "^0.1.3",
-				"parse-semver": "^1.1.1",
-				"read": "^1.0.7",
-				"semver": "^5.1.0",
-				"tmp": "0.0.29",
-				"typed-rest-client": "1.2.0",
-				"url-join": "^1.1.0",
-				"yauzl": "^2.3.1",
-				"yazl": "^2.2.2"
-			},
-			"bin": {
-				"vsce": "out/vsce"
-			},
-			"engines": {
-				"node": ">= 10"
-			}
-		},
-		"node_modules/wrappy": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-			"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-			"dev": true
-		},
-		"node_modules/yauzl": {
-			"version": "2.10.0",
-			"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
-			"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
-			"dev": true,
-			"dependencies": {
-				"buffer-crc32": "~0.2.3",
-				"fd-slicer": "~1.1.0"
-			}
-		},
-		"node_modules/yazl": {
-			"version": "2.5.1",
-			"resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
-			"integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
-			"dev": true,
-			"dependencies": {
-				"buffer-crc32": "~0.2.3"
-			}
-		}
-	},
-	"dependencies": {
-		"@types/node": {
-			"version": "12.20.7",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.7.tgz",
-			"integrity": "sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA==",
-			"dev": true
-		},
-		"ansi-styles": {
-			"version": "3.2.1",
-			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-			"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-			"dev": true,
-			"requires": {
-				"color-convert": "^1.9.0"
-			}
-		},
-		"argparse": {
-			"version": "1.0.10",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-			"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-			"dev": true,
-			"requires": {
-				"sprintf-js": "~1.0.2"
-			}
-		},
-		"azure-devops-node-api": {
-			"version": "7.2.0",
-			"resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-7.2.0.tgz",
-			"integrity": "sha512-pMfGJ6gAQ7LRKTHgiRF+8iaUUeGAI0c8puLaqHLc7B8AR7W6GJLozK9RFeUHFjEGybC9/EB3r67WPd7e46zQ8w==",
-			"dev": true,
-			"requires": {
-				"os": "0.1.1",
-				"tunnel": "0.0.4",
-				"typed-rest-client": "1.2.0",
-				"underscore": "1.8.3"
-			}
-		},
-		"balanced-match": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-			"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-			"dev": true
-		},
-		"boolbase": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-			"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
-			"dev": true
-		},
-		"brace-expansion": {
-			"version": "1.1.11",
-			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-			"dev": true,
-			"requires": {
-				"balanced-match": "^1.0.0",
-				"concat-map": "0.0.1"
-			}
-		},
-		"buffer-crc32": {
-			"version": "0.2.13",
-			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
-			"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
-			"dev": true
-		},
-		"chalk": {
-			"version": "2.4.2",
-			"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-			"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-			"dev": true,
-			"requires": {
-				"ansi-styles": "^3.2.1",
-				"escape-string-regexp": "^1.0.5",
-				"supports-color": "^5.3.0"
-			}
-		},
-		"cheerio": {
-			"version": "1.0.0-rc.5",
-			"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz",
-			"integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==",
-			"dev": true,
-			"requires": {
-				"cheerio-select-tmp": "^0.1.0",
-				"dom-serializer": "~1.2.0",
-				"domhandler": "^4.0.0",
-				"entities": "~2.1.0",
-				"htmlparser2": "^6.0.0",
-				"parse5": "^6.0.0",
-				"parse5-htmlparser2-tree-adapter": "^6.0.0"
-			}
-		},
-		"cheerio-select-tmp": {
-			"version": "0.1.1",
-			"resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz",
-			"integrity": "sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==",
-			"dev": true,
-			"requires": {
-				"css-select": "^3.1.2",
-				"css-what": "^4.0.0",
-				"domelementtype": "^2.1.0",
-				"domhandler": "^4.0.0",
-				"domutils": "^2.4.4"
-			}
-		},
-		"color-convert": {
-			"version": "1.9.3",
-			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-			"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-			"dev": true,
-			"requires": {
-				"color-name": "1.1.3"
-			}
-		},
-		"color-name": {
-			"version": "1.1.3",
-			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-			"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-			"dev": true
-		},
-		"commander": {
-			"version": "6.2.1",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
-			"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
-			"dev": true
-		},
-		"concat-map": {
-			"version": "0.0.1",
-			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-			"dev": true
-		},
-		"css-select": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz",
-			"integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==",
-			"dev": true,
-			"requires": {
-				"boolbase": "^1.0.0",
-				"css-what": "^4.0.0",
-				"domhandler": "^4.0.0",
-				"domutils": "^2.4.3",
-				"nth-check": "^2.0.0"
-			}
-		},
-		"css-what": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz",
-			"integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==",
-			"dev": true
-		},
-		"denodeify": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
-			"integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=",
-			"dev": true
-		},
-		"dom-serializer": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
-			"integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
-			"dev": true,
-			"requires": {
-				"domelementtype": "^2.0.1",
-				"domhandler": "^4.0.0",
-				"entities": "^2.0.0"
-			}
-		},
-		"domelementtype": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
-			"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
-			"dev": true
-		},
-		"domhandler": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.1.0.tgz",
-			"integrity": "sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==",
-			"dev": true,
-			"requires": {
-				"domelementtype": "^2.2.0"
-			}
-		},
-		"domutils": {
-			"version": "2.5.1",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.1.tgz",
-			"integrity": "sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==",
-			"dev": true,
-			"requires": {
-				"dom-serializer": "^1.0.1",
-				"domelementtype": "^2.2.0",
-				"domhandler": "^4.1.0"
-			}
-		},
-		"entities": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
-			"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
-			"dev": true
-		},
-		"escape-string-regexp": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-			"dev": true
-		},
-		"fd-slicer": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
-			"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
-			"dev": true,
-			"requires": {
-				"pend": "~1.2.0"
-			}
-		},
-		"fs.realpath": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-			"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-			"dev": true
-		},
-		"glob": {
-			"version": "7.1.6",
-			"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-			"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-			"dev": true,
-			"requires": {
-				"fs.realpath": "^1.0.0",
-				"inflight": "^1.0.4",
-				"inherits": "2",
-				"minimatch": "^3.0.4",
-				"once": "^1.3.0",
-				"path-is-absolute": "^1.0.0"
-			}
-		},
-		"has-flag": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-			"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-			"dev": true
-		},
-		"htmlparser2": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.1.tgz",
-			"integrity": "sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==",
-			"dev": true,
-			"requires": {
-				"domelementtype": "^2.0.1",
-				"domhandler": "^4.0.0",
-				"domutils": "^2.4.4",
-				"entities": "^2.0.0"
-			}
-		},
-		"inflight": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-			"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-			"dev": true,
-			"requires": {
-				"once": "^1.3.0",
-				"wrappy": "1"
-			}
-		},
-		"inherits": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-			"dev": true
-		},
-		"leven": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
-			"integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
-			"dev": true
-		},
-		"linkify-it": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
-			"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
-			"dev": true,
-			"requires": {
-				"uc.micro": "^1.0.1"
-			}
-		},
-		"lodash": {
-			"version": "4.17.21",
-			"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-			"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-			"dev": true
-		},
-		"markdown-it": {
-			"version": "10.0.0",
-			"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
-			"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
-			"dev": true,
-			"requires": {
-				"argparse": "^1.0.7",
-				"entities": "~2.0.0",
-				"linkify-it": "^2.0.0",
-				"mdurl": "^1.0.1",
-				"uc.micro": "^1.0.5"
-			},
-			"dependencies": {
-				"entities": {
-					"version": "2.0.3",
-					"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
-					"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
-					"dev": true
-				}
-			}
-		},
-		"mdurl": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
-			"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
-			"dev": true
-		},
-		"mime": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-			"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-			"dev": true
-		},
-		"minimatch": {
-			"version": "3.0.4",
-			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-			"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-			"dev": true,
-			"requires": {
-				"brace-expansion": "^1.1.7"
-			}
-		},
-		"mute-stream": {
-			"version": "0.0.8",
-			"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-			"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
-			"dev": true
-		},
-		"nth-check": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
-			"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
-			"dev": true,
-			"requires": {
-				"boolbase": "^1.0.0"
-			}
-		},
-		"once": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-			"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-			"dev": true,
-			"requires": {
-				"wrappy": "1"
-			}
-		},
-		"os": {
-			"version": "0.1.1",
-			"resolved": "https://registry.npmjs.org/os/-/os-0.1.1.tgz",
-			"integrity": "sha1-IIhF6J4ZOtTZcUdLk5R3NqVtE/M=",
-			"dev": true
-		},
-		"os-homedir": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-			"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-			"dev": true
-		},
-		"os-tmpdir": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-			"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
-			"dev": true
-		},
-		"osenv": {
-			"version": "0.1.5",
-			"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-			"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-			"dev": true,
-			"requires": {
-				"os-homedir": "^1.0.0",
-				"os-tmpdir": "^1.0.0"
-			}
-		},
-		"parse-semver": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
-			"integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
-			"dev": true,
-			"requires": {
-				"semver": "^5.1.0"
-			}
-		},
-		"parse5": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
-			"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
-			"dev": true
-		},
-		"parse5-htmlparser2-tree-adapter": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
-			"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
-			"dev": true,
-			"requires": {
-				"parse5": "^6.0.1"
-			}
-		},
-		"path-is-absolute": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-			"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-			"dev": true
-		},
-		"pend": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
-			"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
-			"dev": true
-		},
-		"read": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
-			"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
-			"dev": true,
-			"requires": {
-				"mute-stream": "~0.0.4"
-			}
-		},
-		"semver": {
-			"version": "5.7.1",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-			"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-			"dev": true
-		},
-		"sprintf-js": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-			"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-			"dev": true
-		},
-		"supports-color": {
-			"version": "5.5.0",
-			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-			"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-			"dev": true,
-			"requires": {
-				"has-flag": "^3.0.0"
-			}
-		},
-		"tmp": {
-			"version": "0.0.29",
-			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
-			"integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=",
-			"dev": true,
-			"requires": {
-				"os-tmpdir": "~1.0.1"
-			}
-		},
-		"tunnel": {
-			"version": "0.0.4",
-			"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz",
-			"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=",
-			"dev": true
-		},
-		"typed-rest-client": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.2.0.tgz",
-			"integrity": "sha512-FrUshzZ1yxH8YwGR29PWWnfksLEILbWJydU7zfIRkyH7kAEzB62uMAl2WY6EyolWpLpVHeJGgQm45/MaruaHpw==",
-			"dev": true,
-			"requires": {
-				"tunnel": "0.0.4",
-				"underscore": "1.8.3"
-			}
-		},
-		"typescript": {
-			"version": "4.2.3",
-			"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz",
-			"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==",
-			"dev": true
-		},
-		"uc.micro": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
-			"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
-			"dev": true
-		},
-		"underscore": {
-			"version": "1.8.3",
-			"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
-			"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
-			"dev": true
-		},
-		"url-join": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
-			"integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=",
-			"dev": true
-		},
-		"vsce": {
-			"version": "1.87.1",
-			"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.87.1.tgz",
-			"integrity": "sha512-3tSUWZl9AmhZrqy/UVUpdPODSzBiCGjIr/AMSSgF2PuFLSdrh+6kiOr2Ath7bpQEXOxf55hNgz3qdO5MuEJmww==",
-			"dev": true,
-			"requires": {
-				"azure-devops-node-api": "^7.2.0",
-				"chalk": "^2.4.2",
-				"cheerio": "^1.0.0-rc.1",
-				"commander": "^6.1.0",
-				"denodeify": "^1.2.1",
-				"glob": "^7.0.6",
-				"leven": "^3.1.0",
-				"lodash": "^4.17.15",
-				"markdown-it": "^10.0.0",
-				"mime": "^1.3.4",
-				"minimatch": "^3.0.3",
-				"osenv": "^0.1.3",
-				"parse-semver": "^1.1.1",
-				"read": "^1.0.7",
-				"semver": "^5.1.0",
-				"tmp": "0.0.29",
-				"typed-rest-client": "1.2.0",
-				"url-join": "^1.1.0",
-				"yauzl": "^2.3.1",
-				"yazl": "^2.2.2"
-			}
-		},
-		"wrappy": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-			"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-			"dev": true
-		},
-		"yauzl": {
-			"version": "2.10.0",
-			"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
-			"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
-			"dev": true,
-			"requires": {
-				"buffer-crc32": "~0.2.3",
-				"fd-slicer": "~1.1.0"
-			}
-		},
-		"yazl": {
-			"version": "2.5.1",
-			"resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
-			"integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
-			"dev": true,
-			"requires": {
-				"buffer-crc32": "~0.2.3"
-			}
-		}
-	}
+  "name": "vscode-pv-handlebars-language-server",
+  "version": "0.8.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "vscode-pv-handlebars-language-server",
+      "version": "0.8.0",
+      "hasInstallScript": true,
+      "license": "Apache-2.0",
+      "devDependencies": {
+        "@types/node": "^20.14.2",
+        "typescript": "^5.4.5",
+        "vsce": "^2.15.0"
+      },
+      "engines": {
+        "vscode": "^1.43.0"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "20.14.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
+      "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
+      "dev": true,
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/azure-devops-node-api": {
+      "version": "11.2.0",
+      "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
+      "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
+      "dev": true,
+      "dependencies": {
+        "tunnel": "0.0.6",
+        "typed-rest-client": "^1.8.4"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+      "dev": true,
+      "dependencies": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "node_modules/buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/cheerio": {
+      "version": "1.0.0-rc.12",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+      "dev": true,
+      "dependencies": {
+        "cheerio-select": "^2.1.0",
+        "dom-serializer": "^2.0.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "htmlparser2": "^8.0.1",
+        "parse5": "^7.0.0",
+        "parse5-htmlparser2-tree-adapter": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+      }
+    },
+    "node_modules/cheerio-select": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-select": "^5.1.0",
+        "css-what": "^6.1.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/chownr": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+      "dev": true
+    },
+    "node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "node_modules/commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "node_modules/css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dev": true,
+      "dependencies": {
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+      "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
+    },
+    "node_modules/domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.3.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+      "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+      "dev": true,
+      "dependencies": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.2.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/expand-template": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+      "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+      "dev": true,
+      "dependencies": {
+        "pend": "~1.2.0"
+      }
+    },
+    "node_modules/fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+      "dev": true
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+      "dev": true,
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+      "dev": true
+    },
+    "node_modules/glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/htmlparser2": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+      "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+      "dev": true,
+      "funding": [
+        "https://github.com/fb55/htmlparser2?sponsor=1",
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "dependencies": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "entities": "^4.4.0"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "node_modules/ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "node_modules/keytar": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
+      "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "node-addon-api": "^4.3.0",
+        "prebuild-install": "^7.0.1"
+      }
+    },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "dev": true,
+      "dependencies": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.js"
+      }
+    },
+    "node_modules/markdown-it/node_modules/entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+      "dev": true
+    },
+    "node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true,
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+      "dev": true
+    },
+    "node_modules/mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true
+    },
+    "node_modules/napi-build-utils": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+      "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+      "dev": true
+    },
+    "node_modules/node-abi": {
+      "version": "3.65.0",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
+      "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-abi/node_modules/semver": {
+      "version": "7.6.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+      "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+      "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+      "dev": true
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/parse-semver": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
+      "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
+      "dev": true,
+      "dependencies": {
+        "semver": "^5.1.0"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.4.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+      "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+      "dev": true,
+      "dependencies": {
+        "domhandler": "^5.0.2",
+        "parse5": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "dev": true
+    },
+    "node_modules/prebuild-install": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz",
+      "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==",
+      "dev": true,
+      "dependencies": {
+        "detect-libc": "^2.0.0",
+        "expand-template": "^2.0.3",
+        "github-from-package": "0.0.0",
+        "minimist": "^1.2.3",
+        "mkdirp-classic": "^0.5.3",
+        "napi-build-utils": "^1.0.1",
+        "node-abi": "^3.3.0",
+        "pump": "^3.0.0",
+        "rc": "^1.2.7",
+        "simple-get": "^4.0.0",
+        "tar-fs": "^2.0.0",
+        "tunnel-agent": "^0.6.0"
+      },
+      "bin": {
+        "prebuild-install": "bin.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dev": true,
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.12.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
+      "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
+      "dev": true,
+      "dependencies": {
+        "side-channel": "^1.0.6"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "dependencies": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "bin": {
+        "rc": "cli.js"
+      }
+    },
+    "node_modules/read": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+      "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+      "dev": true,
+      "dependencies": {
+        "mute-stream": "~0.0.4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/sax": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+      "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+      "dev": true
+    },
+    "node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dev": true,
+      "dependencies": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+      "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "object-inspect": "^1.13.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/simple-get": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+      "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "decompress-response": "^6.0.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tar-fs": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+      "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+      "dev": true,
+      "dependencies": {
+        "chownr": "^1.1.1",
+        "mkdirp-classic": "^0.5.2",
+        "pump": "^3.0.0",
+        "tar-stream": "^2.1.4"
+      }
+    },
+    "node_modules/tar-stream": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^4.0.3",
+        "end-of-stream": "^1.4.1",
+        "fs-constants": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+      "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "node_modules/tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+      }
+    },
+    "node_modules/tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/typed-rest-client": {
+      "version": "1.8.11",
+      "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz",
+      "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==",
+      "dev": true,
+      "dependencies": {
+        "qs": "^6.9.1",
+        "tunnel": "0.0.6",
+        "underscore": "^1.12.1"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+      "dev": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+      "dev": true
+    },
+    "node_modules/underscore": {
+      "version": "1.13.6",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
+      "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
+      "dev": true
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "dev": true
+    },
+    "node_modules/url-join": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+      "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+      "dev": true
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true
+    },
+    "node_modules/vsce": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz",
+      "integrity": "sha512-P8E9LAZvBCQnoGoizw65JfGvyMqNGlHdlUXD1VAuxtvYAaHBKLBdKPnpy60XKVDAkQCfmMu53g+gq9FM+ydepw==",
+      "deprecated": "vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead.",
+      "dev": true,
+      "dependencies": {
+        "azure-devops-node-api": "^11.0.1",
+        "chalk": "^2.4.2",
+        "cheerio": "^1.0.0-rc.9",
+        "commander": "^6.1.0",
+        "glob": "^7.0.6",
+        "hosted-git-info": "^4.0.2",
+        "keytar": "^7.7.0",
+        "leven": "^3.1.0",
+        "markdown-it": "^12.3.2",
+        "mime": "^1.3.4",
+        "minimatch": "^3.0.3",
+        "parse-semver": "^1.1.1",
+        "read": "^1.0.7",
+        "semver": "^5.1.0",
+        "tmp": "^0.2.1",
+        "typed-rest-client": "^1.8.4",
+        "url-join": "^4.0.1",
+        "xml2js": "^0.4.23",
+        "yauzl": "^2.3.1",
+        "yazl": "^2.2.2"
+      },
+      "bin": {
+        "vsce": "vsce"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "node_modules/xml2js": {
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+      "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+      "dev": true,
+      "dependencies": {
+        "sax": ">=0.6.0",
+        "xmlbuilder": "~11.0.0"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/xmlbuilder": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+      "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+      "dev": true,
+      "dependencies": {
+        "buffer-crc32": "~0.2.3",
+        "fd-slicer": "~1.1.0"
+      }
+    },
+    "node_modules/yazl": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+      "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+      "dev": true,
+      "dependencies": {
+        "buffer-crc32": "~0.2.3"
+      }
+    }
+  },
+  "dependencies": {
+    "@types/node": {
+      "version": "20.14.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz",
+      "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==",
+      "dev": true,
+      "requires": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "azure-devops-node-api": {
+      "version": "11.2.0",
+      "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz",
+      "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==",
+      "dev": true,
+      "requires": {
+        "tunnel": "0.0.6",
+        "typed-rest-client": "^1.8.4"
+      }
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true
+    },
+    "bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+      "dev": true,
+      "requires": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "dev": true,
+      "requires": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+      "dev": true
+    },
+    "call-bind": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+      "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+      "dev": true,
+      "requires": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "set-function-length": "^1.2.1"
+      }
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "cheerio": {
+      "version": "1.0.0-rc.12",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+      "dev": true,
+      "requires": {
+        "cheerio-select": "^2.1.0",
+        "dom-serializer": "^2.0.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "htmlparser2": "^8.0.1",
+        "parse5": "^7.0.0",
+        "parse5-htmlparser2-tree-adapter": "^7.0.0"
+      }
+    },
+    "cheerio-select": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+      "dev": true,
+      "requires": {
+        "boolbase": "^1.0.0",
+        "css-select": "^5.1.0",
+        "css-what": "^6.1.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1"
+      }
+    },
+    "chownr": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+      "dev": true
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "commander": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+      "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "css-select": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+      "dev": true,
+      "requires": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      }
+    },
+    "css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true
+    },
+    "decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dev": true,
+      "requires": {
+        "mimic-response": "^3.1.0"
+      }
+    },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+      "dev": true
+    },
+    "define-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "requires": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      }
+    },
+    "detect-libc": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+      "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+      "dev": true
+    },
+    "dom-serializer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.2",
+        "entities": "^4.2.0"
+      }
+    },
+    "domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true
+    },
+    "domhandler": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.3.0"
+      }
+    },
+    "domutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+      "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "^2.0.0",
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3"
+      }
+    },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true
+    },
+    "es-define-property": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+      "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.2.4"
+      }
+    },
+    "es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "expand-template": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+      "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+      "dev": true
+    },
+    "fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+      "dev": true,
+      "requires": {
+        "pend": "~1.2.0"
+      }
+    },
+    "fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "dev": true
+    },
+    "get-intrinsic": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+      "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+      "dev": true,
+      "requires": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      }
+    },
+    "github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+      "dev": true
+    },
+    "glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.3"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "requires": {
+        "es-define-property": "^1.0.0"
+      }
+    },
+    "has-proto": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+      "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true
+    },
+    "hasown": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.2"
+      }
+    },
+    "hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "requires": {
+        "lru-cache": "^6.0.0"
+      }
+    },
+    "htmlparser2": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+      "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.3.0",
+        "domhandler": "^5.0.3",
+        "domutils": "^3.0.1",
+        "entities": "^4.4.0"
+      }
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+      "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+      "dev": true
+    },
+    "keytar": {
+      "version": "7.9.0",
+      "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
+      "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
+      "dev": true,
+      "requires": {
+        "node-addon-api": "^4.3.0",
+        "prebuild-install": "^7.0.1"
+      }
+    },
+    "leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true
+    },
+    "linkify-it": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+      "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+      "dev": true,
+      "requires": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "requires": {
+        "yallist": "^4.0.0"
+      }
+    },
+    "markdown-it": {
+      "version": "12.3.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+      "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+      "dev": true,
+      "requires": {
+        "argparse": "^2.0.1",
+        "entities": "~2.1.0",
+        "linkify-it": "^3.0.1",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "dependencies": {
+        "entities": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+          "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+          "dev": true
+        }
+      }
+    },
+    "mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+      "dev": true
+    },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true
+    },
+    "mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true
+    },
+    "mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true
+    },
+    "napi-build-utils": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+      "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
+      "dev": true
+    },
+    "node-abi": {
+      "version": "3.65.0",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
+      "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
+      "dev": true,
+      "requires": {
+        "semver": "^7.3.5"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.6.2",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+          "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+          "dev": true
+        }
+      }
+    },
+    "node-addon-api": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+      "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+      "dev": true
+    },
+    "nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "requires": {
+        "boolbase": "^1.0.0"
+      }
+    },
+    "object-inspect": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+      "dev": true
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "parse-semver": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
+      "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
+      "dev": true,
+      "requires": {
+        "semver": "^5.1.0"
+      }
+    },
+    "parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dev": true,
+      "requires": {
+        "entities": "^4.4.0"
+      }
+    },
+    "parse5-htmlparser2-tree-adapter": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+      "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+      "dev": true,
+      "requires": {
+        "domhandler": "^5.0.2",
+        "parse5": "^7.0.0"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "dev": true
+    },
+    "prebuild-install": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz",
+      "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==",
+      "dev": true,
+      "requires": {
+        "detect-libc": "^2.0.0",
+        "expand-template": "^2.0.3",
+        "github-from-package": "0.0.0",
+        "minimist": "^1.2.3",
+        "mkdirp-classic": "^0.5.3",
+        "napi-build-utils": "^1.0.1",
+        "node-abi": "^3.3.0",
+        "pump": "^3.0.0",
+        "rc": "^1.2.7",
+        "simple-get": "^4.0.0",
+        "tar-fs": "^2.0.0",
+        "tunnel-agent": "^0.6.0"
+      }
+    },
+    "pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "qs": {
+      "version": "6.12.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz",
+      "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==",
+      "dev": true,
+      "requires": {
+        "side-channel": "^1.0.6"
+      }
+    },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      }
+    },
+    "read": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+      "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
+      "dev": true,
+      "requires": {
+        "mute-stream": "~0.0.4"
+      }
+    },
+    "readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true
+    },
+    "sax": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+      "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "dev": true
+    },
+    "set-function-length": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+      "dev": true,
+      "requires": {
+        "define-data-property": "^1.1.4",
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.4",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.2"
+      }
+    },
+    "side-channel": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+      "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.7",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.4",
+        "object-inspect": "^1.13.1"
+      }
+    },
+    "simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "dev": true
+    },
+    "simple-get": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+      "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+      "dev": true,
+      "requires": {
+        "decompress-response": "^6.0.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
+    "string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "tar-fs": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+      "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+      "dev": true,
+      "requires": {
+        "chownr": "^1.1.1",
+        "mkdirp-classic": "^0.5.2",
+        "pump": "^3.0.0",
+        "tar-stream": "^2.1.4"
+      }
+    },
+    "tar-stream": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+      "dev": true,
+      "requires": {
+        "bl": "^4.0.3",
+        "end-of-stream": "^1.4.1",
+        "fs-constants": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1"
+      }
+    },
+    "tmp": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+      "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
+      "dev": true
+    },
+    "tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "dev": true
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "typed-rest-client": {
+      "version": "1.8.11",
+      "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz",
+      "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==",
+      "dev": true,
+      "requires": {
+        "qs": "^6.9.1",
+        "tunnel": "0.0.6",
+        "underscore": "^1.12.1"
+      }
+    },
+    "typescript": {
+      "version": "5.4.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+      "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+      "dev": true
+    },
+    "uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+      "dev": true
+    },
+    "underscore": {
+      "version": "1.13.6",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
+      "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
+      "dev": true
+    },
+    "undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "dev": true
+    },
+    "url-join": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+      "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true
+    },
+    "vsce": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz",
+      "integrity": "sha512-P8E9LAZvBCQnoGoizw65JfGvyMqNGlHdlUXD1VAuxtvYAaHBKLBdKPnpy60XKVDAkQCfmMu53g+gq9FM+ydepw==",
+      "dev": true,
+      "requires": {
+        "azure-devops-node-api": "^11.0.1",
+        "chalk": "^2.4.2",
+        "cheerio": "^1.0.0-rc.9",
+        "commander": "^6.1.0",
+        "glob": "^7.0.6",
+        "hosted-git-info": "^4.0.2",
+        "keytar": "^7.7.0",
+        "leven": "^3.1.0",
+        "markdown-it": "^12.3.2",
+        "mime": "^1.3.4",
+        "minimatch": "^3.0.3",
+        "parse-semver": "^1.1.1",
+        "read": "^1.0.7",
+        "semver": "^5.1.0",
+        "tmp": "^0.2.1",
+        "typed-rest-client": "^1.8.4",
+        "url-join": "^4.0.1",
+        "xml2js": "^0.4.23",
+        "yauzl": "^2.3.1",
+        "yazl": "^2.2.2"
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "xml2js": {
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+      "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+      "dev": true,
+      "requires": {
+        "sax": ">=0.6.0",
+        "xmlbuilder": "~11.0.0"
+      }
+    },
+    "xmlbuilder": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+      "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+      "dev": true
+    },
+    "yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+      "dev": true,
+      "requires": {
+        "buffer-crc32": "~0.2.3",
+        "fd-slicer": "~1.1.0"
+      }
+    },
+    "yazl": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz",
+      "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==",
+      "dev": true,
+      "requires": {
+        "buffer-crc32": "~0.2.3"
+      }
+    }
+  }
 }
diff --git a/packages/vscode-pv-handlebars-language-server/package.json b/packages/vscode-pv-handlebars-language-server/package.json
index 114ec195..acacedc5 100644
--- a/packages/vscode-pv-handlebars-language-server/package.json
+++ b/packages/vscode-pv-handlebars-language-server/package.json
@@ -50,6 +50,12 @@
           "type": "boolean",
           "default": true,
           "description": "Provides completion for css classes in hbs files based on scss files."
+        },
+        "P!VHandlebarsLanguageServer.validateHandlebars": {
+          "scope": "window",
+          "type": "boolean",
+          "default": true,
+          "description": "Marks any parse issue in the handlebars files."
         }
       }
     }
@@ -64,8 +70,8 @@
     "deploy": "vsce publish"
   },
   "devDependencies": {
-    "@types/node": "^12.12.0",
-    "typescript": "^4.2.3",
-    "vsce": "^1.87.0"
+    "@types/node": "^20.14.2",
+    "typescript": "^5.4.5",
+    "vsce": "^2.15.0"
   }
 }
diff --git a/packages/vscode-pv-handlebars-language-server/server/package-lock.json b/packages/vscode-pv-handlebars-language-server/server/package-lock.json
index 03c0e559..575fba22 100644
--- a/packages/vscode-pv-handlebars-language-server/server/package-lock.json
+++ b/packages/vscode-pv-handlebars-language-server/server/package-lock.json
@@ -10,11 +10,12 @@
 				"@babel/traverse": "^7.13.15",
 				"@pro-vision/handlebars-helpers": "^1.1.1",
 				"globby": "^11.0.3",
-				"handlebars": "^4.7.7",
+				"handlebars": "^4.7.8",
 				"handlebars-helpers": "^0.10.0",
+				"js-yaml": "^4.1.0",
 				"postcss-scss": "^3.0.5",
 				"postcss-selector-parser": "^6.0.4",
-				"vscode-languageserver": "^7.0.0",
+				"vscode-languageserver": "^9.0.1",
 				"vscode-languageserver-textdocument": "^1.0.1",
 				"vscode-uri": "^3.0.2",
 				"yaml-front-matter": "^4.1.1"
@@ -22,6 +23,7 @@
 			"devDependencies": {
 				"@types/babel__traverse": "^7.11.1",
 				"@types/handlebars-helpers": "^0.5.2",
+				"@types/js-yaml": "^4.0.9",
 				"@types/vscode": "^1.52.0",
 				"@types/yaml-front-matter": "^4.1.0"
 			},
@@ -219,9 +221,9 @@
 			}
 		},
 		"node_modules/@types/js-yaml": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.0.tgz",
-			"integrity": "sha512-4vlpCM5KPCL5CfGmTbpjwVKbISRYhduEJvvUWsH5EB7QInhEj94XPZ3ts/9FPiLZFqYO0xoW4ZL8z2AabTGgJA==",
+			"version": "4.0.9",
+			"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+			"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
 			"dev": true
 		},
 		"node_modules/@types/node": {
@@ -1254,12 +1256,12 @@
 			}
 		},
 		"node_modules/handlebars": {
-			"version": "4.7.7",
-			"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
-			"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+			"version": "4.7.8",
+			"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
+			"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
 			"dependencies": {
 				"minimist": "^1.2.5",
-				"neo-async": "^2.6.0",
+				"neo-async": "^2.6.2",
 				"source-map": "^0.6.1",
 				"wordwrap": "^1.0.0"
 			},
@@ -1900,17 +1902,21 @@
 			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
 		},
 		"node_modules/js-yaml": {
-			"version": "3.14.1",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-			"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
 			"dependencies": {
-				"argparse": "^1.0.7",
-				"esprima": "^4.0.0"
+				"argparse": "^2.0.1"
 			},
 			"bin": {
 				"js-yaml": "bin/js-yaml.js"
 			}
 		},
+		"node_modules/js-yaml/node_modules/argparse": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+		},
 		"node_modules/jsesc": {
 			"version": "2.5.2",
 			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -3040,31 +3046,31 @@
 			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
 		},
 		"node_modules/vscode-jsonrpc": {
-			"version": "6.0.0",
-			"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz",
-			"integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==",
+			"version": "8.2.0",
+			"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+			"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
 			"engines": {
-				"node": ">=8.0.0 || >=10.0.0"
+				"node": ">=14.0.0"
 			}
 		},
 		"node_modules/vscode-languageserver": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz",
-			"integrity": "sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==",
+			"version": "9.0.1",
+			"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+			"integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
 			"dependencies": {
-				"vscode-languageserver-protocol": "3.16.0"
+				"vscode-languageserver-protocol": "3.17.5"
 			},
 			"bin": {
 				"installServerIntoExtension": "bin/installServerIntoExtension"
 			}
 		},
 		"node_modules/vscode-languageserver-protocol": {
-			"version": "3.16.0",
-			"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz",
-			"integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==",
+			"version": "3.17.5",
+			"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+			"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
 			"dependencies": {
-				"vscode-jsonrpc": "6.0.0",
-				"vscode-languageserver-types": "3.16.0"
+				"vscode-jsonrpc": "8.2.0",
+				"vscode-languageserver-types": "3.17.5"
 			}
 		},
 		"node_modules/vscode-languageserver-textdocument": {
@@ -3073,9 +3079,9 @@
 			"integrity": "sha512-UIcJDjX7IFkck7cSkNNyzIz5FyvpQfY7sdzVy+wkKN/BLaD4DQ0ppXQrKePomCxTS7RrolK1I0pey0bG9eh8dA=="
 		},
 		"node_modules/vscode-languageserver-types": {
-			"version": "3.16.0",
-			"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
-			"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="
+			"version": "3.17.5",
+			"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+			"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
 		},
 		"node_modules/vscode-uri": {
 			"version": "3.0.2",
@@ -3115,6 +3121,18 @@
 				"yaml-front-matter": "bin/js-yaml-front.js"
 			}
 		},
+		"node_modules/yaml-front-matter/node_modules/js-yaml": {
+			"version": "3.14.1",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+			"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+			"dependencies": {
+				"argparse": "^1.0.7",
+				"esprima": "^4.0.0"
+			},
+			"bin": {
+				"js-yaml": "bin/js-yaml.js"
+			}
+		},
 		"node_modules/year": {
 			"version": "0.2.1",
 			"resolved": "https://registry.npmjs.org/year/-/year-0.2.1.tgz",
@@ -3293,9 +3311,9 @@
 			}
 		},
 		"@types/js-yaml": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.0.tgz",
-			"integrity": "sha512-4vlpCM5KPCL5CfGmTbpjwVKbISRYhduEJvvUWsH5EB7QInhEj94XPZ3ts/9FPiLZFqYO0xoW4ZL8z2AabTGgJA==",
+			"version": "4.0.9",
+			"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+			"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
 			"dev": true
 		},
 		"@types/node": {
@@ -4087,12 +4105,12 @@
 			}
 		},
 		"handlebars": {
-			"version": "4.7.7",
-			"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
-			"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
+			"version": "4.7.8",
+			"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
+			"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
 			"requires": {
 				"minimist": "^1.2.5",
-				"neo-async": "^2.6.0",
+				"neo-async": "^2.6.2",
 				"source-map": "^0.6.1",
 				"uglify-js": "^3.1.4",
 				"wordwrap": "^1.0.0"
@@ -4594,12 +4612,18 @@
 			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
 		},
 		"js-yaml": {
-			"version": "3.14.1",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-			"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
 			"requires": {
-				"argparse": "^1.0.7",
-				"esprima": "^4.0.0"
+				"argparse": "^2.0.1"
+			},
+			"dependencies": {
+				"argparse": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+				}
 			}
 		},
 		"jsesc": {
@@ -5453,25 +5477,25 @@
 			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
 		},
 		"vscode-jsonrpc": {
-			"version": "6.0.0",
-			"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz",
-			"integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg=="
+			"version": "8.2.0",
+			"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+			"integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="
 		},
 		"vscode-languageserver": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz",
-			"integrity": "sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==",
+			"version": "9.0.1",
+			"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz",
+			"integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==",
 			"requires": {
-				"vscode-languageserver-protocol": "3.16.0"
+				"vscode-languageserver-protocol": "3.17.5"
 			}
 		},
 		"vscode-languageserver-protocol": {
-			"version": "3.16.0",
-			"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz",
-			"integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==",
+			"version": "3.17.5",
+			"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+			"integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
 			"requires": {
-				"vscode-jsonrpc": "6.0.0",
-				"vscode-languageserver-types": "3.16.0"
+				"vscode-jsonrpc": "8.2.0",
+				"vscode-languageserver-types": "3.17.5"
 			}
 		},
 		"vscode-languageserver-textdocument": {
@@ -5480,9 +5504,9 @@
 			"integrity": "sha512-UIcJDjX7IFkck7cSkNNyzIz5FyvpQfY7sdzVy+wkKN/BLaD4DQ0ppXQrKePomCxTS7RrolK1I0pey0bG9eh8dA=="
 		},
 		"vscode-languageserver-types": {
-			"version": "3.16.0",
-			"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
-			"integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="
+			"version": "3.17.5",
+			"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+			"integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
 		},
 		"vscode-uri": {
 			"version": "3.0.2",
@@ -5511,6 +5535,17 @@
 			"requires": {
 				"commander": "^6.2.0",
 				"js-yaml": "^3.14.1"
+			},
+			"dependencies": {
+				"js-yaml": {
+					"version": "3.14.1",
+					"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+					"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+					"requires": {
+						"argparse": "^1.0.7",
+						"esprima": "^4.0.0"
+					}
+				}
 			}
 		},
 		"year": {
diff --git a/packages/vscode-pv-handlebars-language-server/server/package.json b/packages/vscode-pv-handlebars-language-server/server/package.json
index bc66a071..2225c36e 100644
--- a/packages/vscode-pv-handlebars-language-server/server/package.json
+++ b/packages/vscode-pv-handlebars-language-server/server/package.json
@@ -10,11 +10,11 @@
 		"@babel/traverse": "^7.13.15",
 		"@pro-vision/handlebars-helpers": "^1.1.1",
 		"globby": "^11.0.3",
-		"handlebars": "^4.7.7",
+		"handlebars": "^4.7.8",
 		"handlebars-helpers": "^0.10.0",
 		"postcss-scss": "^3.0.5",
 		"postcss-selector-parser": "^6.0.4",
-		"vscode-languageserver": "^7.0.0",
+		"vscode-languageserver": "^9.0.1",
 		"vscode-languageserver-textdocument": "^1.0.1",
 		"vscode-uri": "^3.0.2",
 		"yaml-front-matter": "^4.1.1"
@@ -22,6 +22,7 @@
 	"devDependencies": {
 		"@types/babel__traverse": "^7.11.1",
 		"@types/handlebars-helpers": "^0.5.2",
+		"@types/js-yaml": "^4.0.9",
 		"@types/vscode": "^1.52.0",
 		"@types/yaml-front-matter": "^4.1.0"
 	}
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
index 0f943144..f7671cdb 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
@@ -5,6 +5,7 @@ interface Settings {
   showHoverInfo: boolean;
   provideCssClassGoToDefinition: boolean;
   provideCssClassCompletion: boolean;
+  validateHandlebars: boolean;
 }
 
 // singleton class to return users extension settings
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/diagnosticProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/diagnosticProvider.ts
new file mode 100644
index 00000000..d920484f
--- /dev/null
+++ b/packages/vscode-pv-handlebars-language-server/server/src/diagnosticProvider.ts
@@ -0,0 +1,162 @@
+import { DiagnosticSeverity, type Diagnostic, type Connection } from "vscode-languageserver/node";
+import { type Range, TextDocument } from "vscode-languageserver-textdocument";
+import * as Handlebars from "handlebars";
+import * as yamlFront from "yaml-front-matter";
+import { type YAMLException } from "js-yaml";
+import { getFilePath, isPVArchetype } from "./helpers";
+import SettingsService from "./SettingsService";
+
+// is shown in the vscode ui, when user hovers on the marked error. To let them know what plugin has marked this as error.
+const DIAGNOSTIC_SOURCE = "p!v Handlebars Language Server";
+
+// Handlebars.parse has normal errors and also this type of error with exact position. e.g. for non matching close tag for block helpers.
+type HandlebarsParseError = Error | Handlebars.Exception;
+type YAMLParseError = Error | YAMLException;
+
+// Highlights any parse errors in the handlebars or their yaml front matter
+class DiagnosticProvide {
+  connection!: Connection;
+  public hasDiagnosticCapability!: boolean;
+
+  init(currentConnection: Connection) {
+    this.connection = currentConnection;
+  }
+
+  unsetDiagnostics(document: TextDocument) {
+    if (this.hasDiagnosticCapability) this.connection!.sendDiagnostics({ uri: document.uri, diagnostics: [] });
+  }
+
+  // debounce showing errors. don't annoy the developer when they are still in the middle of typing.
+  private diagnosticsDelay = 250; // ms
+  private timeout?: NodeJS.Timeout;
+  setDiagnostics(document: TextDocument) {
+    if (this.timeout) clearTimeout(this.timeout);
+    this.timeout = setTimeout(async () => {
+      const settings = await SettingsService.getDocumentSettings(document.uri);
+      if (settings.validateHandlebars && this.hasDiagnosticCapability)
+        this.validateHandlebarsFile(document, this.connection!);
+    }, this.diagnosticsDelay);
+  }
+
+  async validateHandlebarsFile(textDocument: TextDocument, connection: Connection) {
+    const filePath = getFilePath(textDocument);
+    if (!isPVArchetype(filePath)) return;
+
+    let diagnostics: Diagnostic[] = [];
+
+    const fileContent = textDocument.getText();
+    let hbsContent = "";
+    try {
+      hbsContent = yamlFront.loadFront(fileContent).__content.trim();
+    } catch (error) {
+      const err = error as YAMLParseError;
+
+      diagnostics.push({
+        severity: DiagnosticSeverity.Error,
+        range: this.getYamlErrorRange(err),
+        message: err.message,
+        source: DIAGNOSTIC_SOURCE,
+      });
+    }
+    const hbsOffset = fileContent.split("\n").indexOf(hbsContent.split("\n")[0]);
+
+    let err: HandlebarsParseError | null = null;
+
+    try {
+      Handlebars.parse(hbsContent);
+    } catch (error) {
+      err = error as HandlebarsParseError;
+
+      diagnostics.push({
+        severity: DiagnosticSeverity.Error,
+        range: this.getHandlebarsErrorRange(err, hbsOffset),
+        message: err.message,
+        source: DIAGNOSTIC_SOURCE,
+      });
+    }
+
+    connection.sendDiagnostics({
+      uri: textDocument.uri,
+      diagnostics,
+    });
+  }
+
+  /**
+   * depending on the HBS error, this returns the range for that error, taking into account the yaml front matter
+   * @param {HandlebarsParseError} err - exception throng by `Handlebars.parse()`
+   * @param {number} lineOffset - the line number for where the hbs starts (i.e. when file has front matter as well)
+   * @returns {Range}
+   */
+  private getHandlebarsErrorRange(err: HandlebarsParseError, lineOffset: number = 0): Range {
+    // handlebars specific exception with additional info
+    if (err instanceof Handlebars.Exception) {
+      // error lines start from 1. file lines start from 0.
+      const errorLine = err.lineNumber! - 1 + lineOffset;
+
+      // adjust the line number for the yaml front matter in the error message
+      err.message = err.message.replace(String(err.lineNumber), String(errorLine + 1));
+
+      return {
+        start: {
+          line: errorLine,
+          character: err.column!,
+        },
+        end: {
+          line: errorLine,
+          character: err.endColumn!,
+        },
+      };
+    }
+
+    const message = err.message.split("\n")[0];
+    const hbsParseErrorPattern = /Parse error on line (?<lineNumber>\d+):/;
+    const match = message.match(hbsParseErrorPattern);
+    if (match) {
+      const errorLine = Number(match.groups!.lineNumber) - 1 + lineOffset;
+
+      // adjust the line number for the yaml front matter in the error message
+      err.message = err.message.replace(String(match.groups!.lineNumber), String(errorLine + 1));
+
+      return {
+        start: {
+          line: errorLine,
+          character: 0,
+        },
+        end: {
+          line: errorLine,
+          character: 1_000,
+        },
+      };
+    }
+
+    // for unknown type of parse error, mark the start of the file only
+    return { start: { line: lineOffset, character: 0 }, end: { line: lineOffset, character: 0 } };
+  }
+
+  private getYamlErrorRange(err: YAMLParseError) {
+    if (err.name === "YAMLException") {
+      const yamlError = err as YAMLException;
+      err.message = "[YAML] " + yamlError.reason;
+      return {
+        start: {
+          // add 1 line for the "---" at the start of the file
+          line: yamlError.mark.line + 1,
+          character: yamlError.mark.column,
+        },
+        end: {
+          line: yamlError.mark.line + 1,
+          character: yamlError.mark.column,
+        },
+      };
+    }
+
+    err.message = "[YAML] " + err.message;
+    // any other TypeError
+    return {
+      start: { line: 0, character: 0 },
+      end: { line: 0, character: 0 },
+    };
+  }
+}
+
+export default new DiagnosticProvide();
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/server.ts b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
index c0e80484..a8202f1c 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/server.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
@@ -11,6 +11,7 @@ import {
 import { TextDocument } from "vscode-languageserver-textdocument";
 
 import SettingsService from "./SettingsService";
+import DiagnosticProvide from "./diagnosticProvider";
 import { definitionProvider } from "./definitionProvider";
 import { completionProvider } from "./completionProvider";
 import { hoverProvider } from "./hoverProvider";
@@ -20,11 +21,16 @@ import { getFilePath } from "./helpers";
 // Also include all preview / proposed LSP features.
 const connection = createConnection(ProposedFeatures.all);
 SettingsService.init(connection);
+DiagnosticProvide.init(connection);
 
 // Create a simple text document manager.
 const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
+// a list of currently opened documents, by tracking the close and open/content events
+const openDocuments = new Set<TextDocument>();
+
+connection.onInitialize((params: InitializeParams) => {
+  DiagnosticProvide.hasDiagnosticCapability = !!params.capabilities.textDocument?.publishDiagnostics;
 
-connection.onInitialize((_params: InitializeParams) => {
   return {
     capabilities: {
       textDocumentSync: TextDocumentSyncKind.Incremental,
@@ -46,6 +52,10 @@ connection.onInitialize((_params: InitializeParams) => {
       definitionProvider: true,
       // supports hover tooltips
       hoverProvider: true,
+      diagnosticProvider: {
+        interFileDependencies: false,
+        workspaceDiagnostics: false,
+      },
       workspaceFolders: { supported: true },
     },
   };
@@ -58,20 +68,25 @@ connection.onInitialized(() => {
 
 connection.onDidChangeConfiguration(_change => {
   SettingsService.clearDocumentSettingsCache();
+
+  // update diagnostics info for the open files
+  openDocuments.forEach(async document => {
+    const settings = await SettingsService.getDocumentSettings(document.uri);
+    if (settings.validateHandlebars) DiagnosticProvide.setDiagnostics(document);
+    else DiagnosticProvide.unsetDiagnostics(document);
+  });
 });
 
 // This handler provides the initial list of the completion items.
-connection.onCompletion(
-  async (textDocumentPosition: TextDocumentPositionParams): Promise<CompletionItem[] | null> => {
-    const document = documents.get(textDocumentPosition.textDocument.uri);
-
-    if (document) {
-      const filePath = getFilePath(document);
-      if (filePath) return completionProvider(document, textDocumentPosition.position, filePath);
-    }
-    return null;
-  },
-);
+connection.onCompletion(async (textDocumentPosition: TextDocumentPositionParams): Promise<CompletionItem[] | null> => {
+  const document = documents.get(textDocumentPosition.textDocument.uri);
+
+  if (document) {
+    const filePath = getFilePath(document);
+    if (filePath) return completionProvider(document, textDocumentPosition.position, filePath);
+  }
+  return null;
+});
 
 connection.onHover(async ({ textDocument, position }) => {
   const document = documents.get(textDocument.uri);
@@ -93,6 +108,20 @@ connection.onDefinition(({ textDocument, position }) => {
   return null;
 });
 
+// is called when the file is first opened and every time it is modified
+// only supporting push diagnostics
+documents.onDidChangeContent(change => {
+  const document = change.document;
+  DiagnosticProvide.setDiagnostics(document);
+  openDocuments.add(document);
+});
+
+// a document has closed: clear all diagnostics
+documents.onDidClose(event => {
+  DiagnosticProvide.unsetDiagnostics(event.document);
+  openDocuments.delete(event.document);
+});
+
 // Make the text document manager listen on the connection
 // for open, change and close text document events
 documents.listen(connection);

From cbc539ccb5134fd21bb1bd272eab45964eb2f0ad Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Thu, 20 Jun 2024 12:52:17 +0200
Subject: [PATCH 2/7] feat(vscode-pv-handlebars-language-server): add support
 for ui and events info

provide vscode codeLens for all the ui and events (@uiElement, @uiEvent) of the custom element in
the handlebars templates
---
 .../client/src/commands.ts                    |  27 ++
 .../client/src/extension.ts                   |   7 +-
 .../package.json                              |   6 +
 .../server/package-lock.json                  |  32 ---
 .../server/src/SettingsService.ts             |   1 +
 .../server/src/codelensProvider.ts            |  86 ++++++
 .../src/customElementDefinitionProvider.ts    | 246 ++++++++++++++++--
 .../server/src/definitionProvider.ts          |   1 +
 .../server/src/helpers.ts                     |   4 +-
 .../server/src/server.ts                      |  11 +
 10 files changed, 370 insertions(+), 51 deletions(-)
 create mode 100644 packages/vscode-pv-handlebars-language-server/client/src/commands.ts
 create mode 100644 packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts

diff --git a/packages/vscode-pv-handlebars-language-server/client/src/commands.ts b/packages/vscode-pv-handlebars-language-server/client/src/commands.ts
new file mode 100644
index 00000000..a294790c
--- /dev/null
+++ b/packages/vscode-pv-handlebars-language-server/client/src/commands.ts
@@ -0,0 +1,27 @@
+import { commands, window, Location, Uri, Range, Position } from "vscode";
+import { type Location as LSLocation } from "vscode-languageclient/node";
+
+/**
+ * converts locations of type vscode-languageclient/node to `Location` from `vscode` (client) extension
+ *
+ * @param {LSLocation} locations - code locations
+ * @returns {Location}
+ */
+function castLocationsType({ uri, range }: LSLocation) {
+  return new Location(
+    Uri.file(uri),
+    new Range(new Position(range.start.line, range.start.character), new Position(range.end.line, range.end.character)),
+  );
+}
+
+// trigger vscode build-in command to navigate to the given code location(s)
+export function goToLocation(location: LSLocation) {
+  commands.executeCommand(
+    "editor.action.goToLocations",
+    window.activeTextEditor.document.uri, // from
+    window.activeTextEditor.selection.active,
+    [castLocationsType(location)], // to
+    "peek", // for multiple options (if we use LSLocation[]), show the list and allow the user to choose
+    "",
+  );
+}
diff --git a/packages/vscode-pv-handlebars-language-server/client/src/extension.ts b/packages/vscode-pv-handlebars-language-server/client/src/extension.ts
index 4bfdcbeb..491d0734 100644
--- a/packages/vscode-pv-handlebars-language-server/client/src/extension.ts
+++ b/packages/vscode-pv-handlebars-language-server/client/src/extension.ts
@@ -1,7 +1,8 @@
 import * as path from "path";
-import type { ExtensionContext } from "vscode";
+import { type ExtensionContext, commands } from "vscode";
 import { LanguageClient, TransportKind } from "vscode-languageclient/node";
 import type { LanguageClientOptions, ServerOptions } from "vscode-languageclient/node";
+import { goToLocation } from "./commands";
 
 let client: LanguageClient;
 
@@ -39,6 +40,10 @@ export function activate(context: ExtensionContext): void {
 
   // Start the client. This will also launch the server
   client.start();
+
+  // running "editor.action.goToLocations" command directly in server code didn't work,
+  // custom command to get the arguments and execute command from the client code
+  commands.registerCommand("P!VHandlebarsLanguageServer.codelensAction", goToLocation);
 }
 
 export function deactivate(): Thenable<void> | undefined {
diff --git a/packages/vscode-pv-handlebars-language-server/package.json b/packages/vscode-pv-handlebars-language-server/package.json
index acacedc5..dc838d30 100644
--- a/packages/vscode-pv-handlebars-language-server/package.json
+++ b/packages/vscode-pv-handlebars-language-server/package.json
@@ -56,6 +56,12 @@
           "type": "boolean",
           "default": true,
           "description": "Marks any parse issue in the handlebars files."
+        },
+        "P!VHandlebarsLanguageServer.showUIAndEvents": {
+          "scope": "window",
+          "type": "boolean",
+          "default": true,
+          "description": "Show ui and event info for html elements used by the kluntje custom elements in the hbs files."
         }
       }
     }
diff --git a/packages/vscode-pv-handlebars-language-server/server/package-lock.json b/packages/vscode-pv-handlebars-language-server/server/package-lock.json
index 575fba22..a3567aa3 100644
--- a/packages/vscode-pv-handlebars-language-server/server/package-lock.json
+++ b/packages/vscode-pv-handlebars-language-server/server/package-lock.json
@@ -12,7 +12,6 @@
 				"globby": "^11.0.3",
 				"handlebars": "^4.7.8",
 				"handlebars-helpers": "^0.10.0",
-				"js-yaml": "^4.1.0",
 				"postcss-scss": "^3.0.5",
 				"postcss-selector-parser": "^6.0.4",
 				"vscode-languageserver": "^9.0.1",
@@ -1901,22 +1900,6 @@
 			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
 			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
 		},
-		"node_modules/js-yaml": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-			"dependencies": {
-				"argparse": "^2.0.1"
-			},
-			"bin": {
-				"js-yaml": "bin/js-yaml.js"
-			}
-		},
-		"node_modules/js-yaml/node_modules/argparse": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
-		},
 		"node_modules/jsesc": {
 			"version": "2.5.2",
 			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -4611,21 +4594,6 @@
 			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
 			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
 		},
-		"js-yaml": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-			"requires": {
-				"argparse": "^2.0.1"
-			},
-			"dependencies": {
-				"argparse": {
-					"version": "2.0.1",
-					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
-				}
-			}
-		},
 		"jsesc": {
 			"version": "2.5.2",
 			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
index f7671cdb..6b59b0d2 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
@@ -6,6 +6,7 @@ interface Settings {
   provideCssClassGoToDefinition: boolean;
   provideCssClassCompletion: boolean;
   validateHandlebars: boolean;
+  showUIAndEvents: boolean;
 }
 
 // singleton class to return users extension settings
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
new file mode 100644
index 00000000..b4550db4
--- /dev/null
+++ b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
@@ -0,0 +1,86 @@
+import { basename, dirname } from "path";
+import { Range, Position, Location } from "vscode-languageserver/node";
+import { TextDocument } from "vscode-languageserver-textdocument";
+import globby = require("globby");
+import { getCustomElementsUIAndEvents } from "./customElementDefinitionProvider";
+import { getFilePath } from "./helpers";
+
+const classAndTagRegEx = () => /<(?<tagName>[a-zA-Z0-9_-]+)[^>]*?(class="(?<className>[^"]*))?"/g;
+
+/**
+ * creates an object that can be consumed by onCodeLens request handler (see vscode's `CodeLens` interface for more info)
+ *
+ * @param {object} param0
+ * @param {number} param0.line - zero based line number of where the codeLens should be shown
+ * @param {string} param0.title - text of the code Lens
+ * @param {[number, number]} param0.location - clicking on the codeLens should bring the user to this code location [line, character]
+ * @param {string} param0.uri - path to the the file which user is moved to once they click on the codeLens
+ * @returns
+ */
+const createLens = ({
+  line,
+  title,
+  location,
+  uri,
+}: {
+  line: number;
+  title: string;
+  location: [number, number];
+  uri: string;
+}) => ({
+  range: Range.create(Position.create(line, 0), Position.create(line, 0)),
+  command: {
+    title,
+    command: "P!VHandlebarsLanguageServer.codelensAction",
+    arguments: [Location.create(uri, Range.create(Position.create(...location), Position.create(...location)))],
+  },
+});
+
+// finds all @uiElement, @uiEvent etc and highlights those in the hbs
+export async function codelensProvider(textDocument: TextDocument) {
+  const codeLenses = [];
+
+  const filePath = getFilePath(textDocument);
+  const dir = dirname(filePath);
+  const name = basename(dir);
+
+  // assuming the main custom element has the same as the directory name of the current hbs file
+  const customElementFile = await globby(`${dir}/${name}.ts`);
+  if (!customElementFile.length) return null;
+
+  const cePath = customElementFile[0];
+
+  const selectors = await getCustomElementsUIAndEvents(customElementFile[0]);
+  if (!selectors) return null;
+
+  const content = textDocument.getText();
+  const regex = classAndTagRegEx();
+  let matches;
+
+  while ((matches = regex.exec(content)) !== null) {
+    for (const [selector, item] of Object.entries(selectors)) {
+      const classMatch =
+        selector.startsWith(".") && matches.groups!.className?.split(" ").includes(selector.replace(/^./, ""));
+      const tagMatch = matches.groups!.tagName === selector;
+      if (classMatch || tagMatch) {
+        const line = content.substring(0, matches.index).split("\n").length - 1;
+
+        if (item.ui) {
+          codeLenses.push(
+            createLens({
+              line,
+              title: item.ui.name + (item.ui.isArray ? "[]" : ""),
+              location: item.ui.location,
+              uri: cePath,
+            }),
+          );
+        }
+        item.events.forEach(ev => {
+          codeLenses.push(createLens({ line, title: "@" + ev.name, location: ev.location, uri: cePath }));
+        });
+      }
+    }
+  }
+
+  return codeLenses;
+}
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/customElementDefinitionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/customElementDefinitionProvider.ts
index d913ba09..c8ea0582 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/customElementDefinitionProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/customElementDefinitionProvider.ts
@@ -1,34 +1,248 @@
 import { Location, Range } from "vscode-languageserver/node";
 import { URI } from "vscode-uri";
 import * as babelParser from "@babel/parser";
-import babelTraverse from "@babel/traverse";
+import babelTraverse, { type NodePath } from "@babel/traverse";
+import type {
+  CallExpression,
+  Identifier,
+  StringLiteral,
+  ObjectExpression,
+  ObjectProperty,
+  ClassMethod,
+  ClassProperty,
+} from "@babel/types";
 
 import { readFile } from "./helpers";
 
-export async function getCustomElementsClassDeclarationLocation(filePath: string): Promise<Location | null> {
+// get AST of a typescript file
+async function getAST(filePath: string) {
   try {
     const code = await readFile(filePath, { encoding: "utf-8" });
     const ast = babelParser.parse(code, {
       sourceType: "module",
       plugins: ["typescript", "classProperties", "decorators-legacy"],
     });
-    let result: [number, number, number, number];
-    babelTraverse(ast, {
-      // get the start position of the CE class
-      ClassDeclaration: nodePath => {
-        result = [
-          // vscode needs zero based indices
-          nodePath.node.loc?.start.line! - 1, nodePath.node.loc?.start.column!,
-          nodePath.node.loc?.end.line! - 1, nodePath.node.loc?.end.column!,
-        ];
-      },
-    });
-
-    // @ts-ignore
-    if (result !== undefined) return Location.create(URI.file(filePath).toString(), Range.create(...result));
+    return ast;
   } catch {
     // parse error when code has some syntax issues
+    return null;
   }
+}
+
+export async function isKluntjeComponent(filePath: string) {
+  const ast = await getAST(filePath);
+  if (!ast) return null;
+
+  let result = false;
+  babelTraverse(ast, {
+    ImportDeclaration(node) {
+      // importing any modules from kluntje/core is a good enough indicator for a custom element being based a kluntje component
+      if (node.node.source.value === "@kluntje/core") result = true;
+    },
+  });
+
+  return result;
+}
+
+// provides the start and end location of the custom element declaration, assuming it is the only class in the file.
+export async function getCustomElementsClassDeclarationLocation(filePath: string): Promise<Location | null> {
+  const ast = await getAST(filePath);
+  if (!ast) return null;
+
+  let result: [number, number, number, number];
+
+  babelTraverse(ast, {
+    // get the start position of the CE class
+    ClassDeclaration: nodePath => {
+      result = [
+        // vscode needs zero based indices
+        nodePath.node.loc?.start.line! - 1,
+        nodePath.node.loc?.start.column!,
+        nodePath.node.loc?.end.line! - 1,
+        nodePath.node.loc?.end.column!,
+      ];
+    },
+  });
+
+  // @ts-ignore
+  if (result !== undefined) return Location.create(URI.file(filePath).toString(), Range.create(...result));
 
   return null;
 }
+
+// [line, character]
+type CodeLocation = [number, number];
+
+/*
+  @uiElements(".e-btn")
+  ctas: HTMLElement[]
+*/
+type UiInfo = {
+  name: string; // e.g. "ctas"
+  selector: string; // e.g. ".e-btn"
+  isArray: boolean; // i.e. using `@uiElements` instead of `@uiElement`
+  location: CodeLocation;
+};
+
+/*
+  @uiEvent("ctas", "click")
+  handleCtaClick(){}
+*/
+type EventInfo = {
+  name: string; // e.g. "click"
+  methodName: string; // e.g. "handleCtaClick"
+  location: CodeLocation;
+};
+
+// returns a list of used @uiElement(s), @uiEvents, etc. and their location in the file
+export async function getCustomElementsUIAndEvents(filePath: string) {
+  const ast = await getAST(filePath);
+  if (!ast) return null;
+
+  const uis: Array<UiInfo> = [];
+
+  const events: Array<{
+    events: Array<EventInfo>;
+    target: string; // e.g. "cta" or ".e-btn" in case of `@eventListener`
+  }> = [];
+
+  function extractUiAndEvent(nodePath: NodePath<ClassMethod> | NodePath<ClassProperty>) {
+    const propName = (nodePath.node.key as Identifier).name;
+    // currently all kluntje component decorators are functions
+    const decorators = nodePath.node.decorators
+      ?.filter(decoratorNode => decoratorNode.expression.type === "CallExpression")
+      .map(decoratorNode => decoratorNode.expression as CallExpression);
+
+    if (decorators) {
+      decorators.forEach(decorator => {
+        const name = (decorator.callee as Identifier).name;
+        // `@uiElement(".selector")` and `@uiElements(".selector")`
+        // ignore e.g. `@uiElement(SOME_VARIABLE)`
+        if ((name === "uiElement" || name === "uiElements") && decorator.arguments[0].type === "StringLiteral") {
+          const selector = decorator.arguments[0].value;
+          uis.push({
+            name: propName,
+            selector,
+            location: [nodePath.node.key.loc!.start.line! - 1, nodePath.node.key.loc!.start.column!],
+            isArray: name === "uiElements",
+          });
+        }
+        // @uiEvent("cta", "click") & @uiEvent("cta", SOME_EVENT)
+        else if (name === "uiEvent") {
+          // ignore any `@uiEvent(SOME_VARIABLE, )`
+          if (decorator.arguments[0].type !== "StringLiteral") return;
+          if (decorator.arguments[1].type !== "StringLiteral" && decorator.arguments[1].type !== "Identifier") return;
+
+          const args = decorator.arguments as StringLiteral[];
+          const elementName = decorator.arguments[0] as StringLiteral;
+          const eventName = decorator.arguments[1] as StringLiteral | Identifier;
+          let eventNames: string[] = [];
+          // e.g. @uiEvent(, "focus input")
+          if (eventName.type === "StringLiteral") eventNames = eventName.value.split(" ");
+          // e.g. `@uiEvent(, SOME_VARIABLE)`
+          else if (eventName.type === "Identifier") eventNames = [eventName.name];
+          events.push({
+            target: elementName.value,
+            events: eventNames.map(eventName => ({
+              name: eventName,
+              methodName: propName,
+              location: [args[1].loc!.start.line! - 1, args[1].loc!.start.column! + 1],
+            })),
+          });
+        }
+        // @eventListener({event: "click", target: ".selector"}) and @eventListener({events: ["click", "scroll"], target: ".selector"})
+        else if (name === "eventListener") {
+          const properties = (decorator.arguments as ObjectExpression[])[0].properties as ObjectProperty[];
+          let evs: string[] = [];
+          let target: string = "";
+
+          properties.forEach(prop => {
+            // ignore `target(){}`
+            if (prop.type !== "ObjectProperty" || prop.key.type !== "Identifier") return;
+
+            if (prop.key.name === "event" && prop.value.type === "StringLiteral") {
+              evs.push(prop.value.value);
+            } else if (prop.key.name === "events" && prop.value.type === "ArrayExpression") {
+              prop.value.elements.forEach(val => {
+                if (val?.type === "StringLiteral") evs.push(val.value);
+              });
+            } else if (prop.key.name === "target" && prop.value.type === "StringLiteral") {
+              target = prop.value.value;
+            }
+          });
+
+          if (target && evs.length) {
+            events.push({
+              target,
+              events: evs.map(name => ({
+                name,
+                methodName: propName,
+                location: [
+                  // pass the location of the decorator itself, instead of each event string individually which is more work
+                  // vscode needs zero based indices
+                  decorator.loc?.start.line! - 1,
+                  // 1 to left for the "@" character
+                  decorator.loc?.start.column! - 1,
+                ],
+              })),
+            });
+          }
+        }
+      });
+    }
+  }
+
+  babelTraverse(ast, {
+    ClassProperty(nodePath) {
+      extractUiAndEvent(nodePath);
+    },
+
+    ClassMethod(nodePath) {
+      extractUiAndEvent(nodePath);
+    },
+  });
+
+  const selectors: Record<
+    string, // e.g. ".e-btn"
+    {
+      ui?: {
+        name: string; // e.g. ctas
+        location: CodeLocation;
+        isArray: boolean;
+      };
+      events: Array<EventInfo>;
+    }
+  > = {};
+
+  // e.g. "button, .e-cta" => ["button", ".e-cta"]
+  const getSelectors = (value: string) => value.split(",").map(s => s.trim());
+
+  uis.forEach(({ name, selector, location, isArray }) => {
+    getSelectors(selector).forEach(
+      s =>
+        (selectors[s] = {
+          ui: {
+            name,
+            location,
+            isArray,
+          },
+          events: [],
+        }),
+    );
+  });
+
+  events.forEach(event => {
+    if (event.target) {
+      const item = Object.entries(selectors).find(([_s, value]) => value.ui?.name === event.target);
+      if (item) item[1].events.push(...event.events);
+      else {
+        getSelectors(event.target).forEach(s => {
+          selectors[s] = selectors[s] ?? { events: [] };
+          selectors[s].events.push(...event.events);
+        });
+      }
+    }
+  });
+
+  return selectors;
+}
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
index ee65897b..6b170759 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
@@ -133,6 +133,7 @@ export async function definitionProvider(
   }
   // <custom-element
   else if (/<\/?[a-z]+[a-z0-9_-]+$/.test(textBefore) || / is="[a-z]+[a-z0-9_-]+$/.test(textBefore)) {
+    // assuming filename and custom tag are the same
     const customElementFile = await globby(`${componentsRootPath}/**/${symbolName}.ts`);
     if (customElementFile.length) {
       const cePath = customElementFile[0];
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
index e882f67f..b9e87ca6 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
@@ -4,7 +4,7 @@ import { promisify } from "util";
 import * as globby from "globby";
 import * as yamlFront from "yaml-front-matter";
 import { URI } from "vscode-uri";
-import type { Position } from "vscode-languageserver/node";
+import type { Position, TextDocumentIdentifier } from "vscode-languageserver/node";
 import type { TextDocument } from "vscode-languageserver-textdocument";
 
 interface PVConfig {
@@ -49,7 +49,7 @@ export function basename(filePath: string): string {
  * @param {TextDocument} document
  * @returns {string}
  */
-export function getFilePath(document: TextDocument): string {
+export function getFilePath(document: TextDocument | TextDocumentIdentifier): string {
   const fsPath = URI.parse(document.uri).fsPath;
   // convert to unix paths
   return toUnixPath(fsPath);
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/server.ts b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
index a8202f1c..bbb407ec 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/server.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
@@ -16,6 +16,7 @@ import { definitionProvider } from "./definitionProvider";
 import { completionProvider } from "./completionProvider";
 import { hoverProvider } from "./hoverProvider";
 import { getFilePath } from "./helpers";
+import { codelensProvider } from "./codelensProvider";
 
 // Create a connection for the server, using Node's IPC as a transport.
 // Also include all preview / proposed LSP features.
@@ -57,6 +58,9 @@ connection.onInitialize((params: InitializeParams) => {
         workspaceDiagnostics: false,
       },
       workspaceFolders: { supported: true },
+      codeLensProvider: {
+        resolveProvider: true,
+      },
     },
   };
 });
@@ -108,6 +112,13 @@ connection.onDefinition(({ textDocument, position }) => {
   return null;
 });
 
+connection.onCodeLens(async ({ textDocument }) => {
+  const document = documents.get(textDocument.uri);
+  const settings = await SettingsService.getDocumentSettings(textDocument.uri);
+
+  if (document && settings.showUIAndEvents) return codelensProvider(document);
+});
+
 // is called when the file is first opened and every time it is modified
 // only supporting push diagnostics
 documents.onDidChangeContent(change => {

From e176ca30f4dfb1d78b49f8d34c3d0c98b3a827f8 Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Thu, 20 Jun 2024 22:58:56 +0200
Subject: [PATCH 3/7] feat(vscode-pv-handlebars-language-server): add ui
 auto-complitation capacity for kluntje components

extend vscode plugin's capibility, to suggest css classes for uiElement and ui propertie names for
uiEvents based on the component hbs file
---
 .../client/src/extension.ts                   |   7 +-
 .../client/tsconfig.json                      |   4 +-
 .../package.json                              |   9 +-
 .../server/src/SettingsService.ts             |   1 +
 .../server/src/codelensProvider.ts            |   4 +-
 .../server/src/helpers.ts                     | 116 ++++++++++++++++--
 .../server/src/rgx.ts                         |  18 +++
 .../server/src/server.ts                      |  43 ++++---
 .../server/src/tsCompletionProvider.ts        |  90 ++++++++++++++
 .../server/tsconfig.json                      |   4 +-
 .../tsconfig.json                             |   4 +-
 11 files changed, 266 insertions(+), 34 deletions(-)
 create mode 100644 packages/vscode-pv-handlebars-language-server/server/src/rgx.ts
 create mode 100644 packages/vscode-pv-handlebars-language-server/server/src/tsCompletionProvider.ts

diff --git a/packages/vscode-pv-handlebars-language-server/client/src/extension.ts b/packages/vscode-pv-handlebars-language-server/client/src/extension.ts
index 491d0734..55fad86c 100644
--- a/packages/vscode-pv-handlebars-language-server/client/src/extension.ts
+++ b/packages/vscode-pv-handlebars-language-server/client/src/extension.ts
@@ -26,8 +26,11 @@ export function activate(context: ExtensionContext): void {
 
   // Options to control the language client
   const clientOptions: LanguageClientOptions = {
-    // Register the server for Handlebars documents
-    documentSelector: [{ scheme: "file", language: "handlebars" }],
+    // Register the server for Handlebars documents and Typescript
+    documentSelector: [
+      { scheme: "file", language: "handlebars" },
+      { scheme: "file", language: "typescript" },
+    ],
   };
 
   // Create the language client and start the client.
diff --git a/packages/vscode-pv-handlebars-language-server/client/tsconfig.json b/packages/vscode-pv-handlebars-language-server/client/tsconfig.json
index b216b86e..8312a06e 100644
--- a/packages/vscode-pv-handlebars-language-server/client/tsconfig.json
+++ b/packages/vscode-pv-handlebars-language-server/client/tsconfig.json
@@ -1,7 +1,7 @@
 {
   "compilerOptions": {
-    "target": "es2019",
-    "lib": ["ES2019"],
+    "target": "ESNext",
+    "lib": ["ESNext"],
     "module": "commonjs",
     "moduleResolution": "node",
     "outDir": "out",
diff --git a/packages/vscode-pv-handlebars-language-server/package.json b/packages/vscode-pv-handlebars-language-server/package.json
index dc838d30..b535aaf3 100644
--- a/packages/vscode-pv-handlebars-language-server/package.json
+++ b/packages/vscode-pv-handlebars-language-server/package.json
@@ -25,7 +25,8 @@
     "vscode": "^1.43.0"
   },
   "activationEvents": [
-    "onLanguage:handlebars"
+    "onLanguage:handlebars",
+    "onLanguage:typescript"
   ],
   "main": "./client/out/extension",
   "contributes": {
@@ -62,6 +63,12 @@
           "type": "boolean",
           "default": true,
           "description": "Show ui and event info for html elements used by the kluntje custom elements in the hbs files."
+        },
+        "P!VHandlebarsLanguageServer.provideUiCompletionInTypescript": {
+          "scope": "window",
+          "type": "boolean",
+          "default": true,
+          "description": "For @klutnje componets, suggest the css classes and ui names in the @uiElement and @uiEvent."
         }
       }
     }
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
index 6b59b0d2..eab78690 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
@@ -7,6 +7,7 @@ interface Settings {
   provideCssClassCompletion: boolean;
   validateHandlebars: boolean;
   showUIAndEvents: boolean;
+  provideUiCompletionInTypescript: boolean;
 }
 
 // singleton class to return users extension settings
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
index b4550db4..61b85b19 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
@@ -4,8 +4,8 @@ import { TextDocument } from "vscode-languageserver-textdocument";
 import globby = require("globby");
 import { getCustomElementsUIAndEvents } from "./customElementDefinitionProvider";
 import { getFilePath } from "./helpers";
+import rgx from "./rgx";
 
-const classAndTagRegEx = () => /<(?<tagName>[a-zA-Z0-9_-]+)[^>]*?(class="(?<className>[^"]*))?"/g;
 
 /**
  * creates an object that can be consumed by onCodeLens request handler (see vscode's `CodeLens` interface for more info)
@@ -54,7 +54,7 @@ export async function codelensProvider(textDocument: TextDocument) {
   if (!selectors) return null;
 
   const content = textDocument.getText();
-  const regex = classAndTagRegEx();
+  const regex = new RegExp(rgx.hbs.classNamesAndTags(), "g");
   let matches;
 
   while ((matches = regex.exec(content)) !== null) {
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
index b9e87ca6..908fd393 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
@@ -6,6 +6,7 @@ import * as yamlFront from "yaml-front-matter";
 import { URI } from "vscode-uri";
 import type { Position, TextDocumentIdentifier } from "vscode-languageserver/node";
 import type { TextDocument } from "vscode-languageserver-textdocument";
+import rgx from "./rgx";
 
 interface PVConfig {
   hbsHelperSrc?: string;
@@ -55,15 +56,25 @@ export function getFilePath(document: TextDocument | TextDocumentIdentifier): st
   return toUnixPath(fsPath);
 }
 
+export function isHandlebarsFile(uri: string) {
+  return uri.endsWith(".hbs");
+}
+
+export function isTypescriptFile(uri: string) {
+  return uri.endsWith(".ts");
+}
+
 /**
  * returns true if the .hbs file's path seams to belong to a repo with the p!v fe archetype structure
  * @param {string} templatePath - absolute path (with unix separators) to a hbs file
  * @returns {boolean}
  */
 export function isPVArchetype(templatePath: string): boolean {
-  return templatePath.includes("/frontend/src/components")
-   || templatePath.includes("/frontend/src/pages")
-   || templatePath.includes("/frontend/src/layouts");
+  return (
+    templatePath.includes("/frontend/src/components") ||
+    templatePath.includes("/frontend/src/pages") ||
+    templatePath.includes("/frontend/src/layouts")
+  );
 }
 
 /**
@@ -149,7 +160,10 @@ export async function getCustomHelperFiles(componentsRootPath: string): Promise<
   return helperPaths.map(filePath => ({ path: filePath, name: path.basename(filePath, ".js") }));
 }
 
-interface LayoutFiles {lsg?: {[name: string]: string}, pages?: {[name: string]: string}}
+interface LayoutFiles {
+  lsg?: { [name: string]: string };
+  pages?: { [name: string]: string };
+}
 
 // list of hbs files which are used in assemble-lite as layouts for lsg components or pages
 export async function getLayoutFiles(componentsRootPath: string): Promise<LayoutFiles | null> {
@@ -158,7 +172,7 @@ export async function getLayoutFiles(componentsRootPath: string): Promise<Layout
 
   if (pvConfig === null) return null;
 
-  const layouts: Array<{name: "lsg" | "pages", dir: string | undefined}> = [
+  const layouts: Array<{ name: "lsg" | "pages"; dir: string | undefined }> = [
     {
       name: "lsg",
       dir: pvConfig.lsgTemplatesSrc,
@@ -171,9 +185,9 @@ export async function getLayoutFiles(componentsRootPath: string): Promise<Layout
 
   const layoutFiles: LayoutFiles = {};
 
-  for (const {name, dir} of layouts) {
+  for (const { name, dir } of layouts) {
     if (dir) {
-      const pageLayoutsGlob = toUnixPath(path.join(frontendRootPath , dir, "/**/*.hbs"));
+      const pageLayoutsGlob = toUnixPath(path.join(frontendRootPath, dir, "/**/*.hbs"));
       const layouts = await globby(pageLayoutsGlob);
       layoutFiles[name] = Object.fromEntries(layouts.map(filePath => [path.basename(filePath, ".hbs"), filePath]));
     }
@@ -258,7 +272,7 @@ export function isPartialParameter(text: string): boolean {
  * @returns {string}
  */
 export async function getHbsContent(filePath: string): Promise<string> {
-  const fileContent = await readFile(filePath, { encoding: "utf-8" });
+  const fileContent = await getFileContent(filePath);
   const hbsCode = yamlFront.loadFront(fileContent).__content.trim();
   return hbsCode;
 }
@@ -281,3 +295,89 @@ export function getCurrentSymbolsName(document: TextDocument, position: Position
 
   return symbolName;
 }
+
+// returns all the css classes in for the hbs template of the given ts file
+// and the hbs partials it is referencing directly or indirectly
+export async function getCssClasses(filePath: string) {
+  const dir = path.dirname(filePath);
+  const name = basename(filePath);
+
+  const cssClasses = [];
+  // assuming the markup example of the custom element defined in foo-bar.ts is in foo-bar.hbs
+  const hbsTemplate = (await globby(`${dir}/**/${name}.hbs`))[0];
+  if (!hbsTemplate) return [];
+
+  const templates = await getNestedTemplates(hbsTemplate);
+
+  for (const hbsFile of templates) {
+    const fileContent = hbsFile.fileContent;
+    const regex = new RegExp(rgx.hbs.classNamesAndTags(), "g");
+    let matches;
+    while ((matches = regex.exec(fileContent)) !== null) {
+      if (!matches.groups!.className) continue;
+
+      const contentBefore = fileContent.substring(0, matches.index);
+      const line = contentBefore.split("\n").length - 1;
+      const character = matches.index - contentBefore.lastIndexOf("\n");
+      let className = matches.groups!.className;
+      className = className.replace(/{{.*?}}/g, "");
+      const classes = className
+        .split(" ")
+        .map(c => c.trim())
+        .filter(c => c !== "");
+      cssClasses.push(
+        ...classes.map(clss => ({
+          className: clss,
+          location: {
+            filePath,
+            line,
+            character,
+          },
+        })),
+      );
+    }
+  }
+
+  return cssClasses;
+}
+
+// returns a list of all partials used in the given hbs content
+export async function getReferencedHbsPartialNames(fileContent: string) {
+  return Array.from(fileContent.matchAll(rgx.hbs.partials())).map(match => match.groups!.partial);
+}
+
+// returns a list of hbs files that are directly or indirectly via partial referenced in the given file(s)
+export async function getNestedTemplates(hbsTemplate: string) {
+  const visited: string[] = [];
+  async function searchRecursive(filePaths: string | string[]) {
+    const results: Array<{ filePath: string; fileContent: string }> = [];
+
+    if (Array.isArray(filePaths)) {
+      for (const filePath of filePaths) {
+        results.push(...(await searchRecursive(filePath)));
+      }
+    } else if (!visited.includes(filePaths)) {
+      visited.push(filePaths);
+      const fileContent = await getFileContent(filePaths);
+      results.push({ filePath: filePaths, fileContent });
+
+      let componentsRootPath;
+      try {
+        componentsRootPath = getComponentsRootPath(filePaths);
+      } catch (_err) {
+        // err e.g. in case of it not having p!v folder structure
+        return results;
+      }
+
+      const partials = await getReferencedHbsPartialNames(fileContent);
+      for (const partial of partials) {
+        const partialPaths = await globby(`${componentsRootPath}/**/${partial}.hbs`);
+        results.push(...(await searchRecursive(partialPaths)));
+      }
+    }
+
+    return results;
+  }
+
+  return searchRecursive(hbsTemplate);
+}
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts b/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts
new file mode 100644
index 00000000..0938af28
--- /dev/null
+++ b/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts
@@ -0,0 +1,18 @@
+export default {
+  ts: {
+    // `@uiElements(".optional` | `@uiElement("`
+    endsWithUiDecoratorSelector: () => /@uiElements?\("[^"]*\.?$/,
+    // `@uiElements(".selector") ctas`
+    uiDecoratorPropertyName: () => /@uiElements?\(.+?\)\s*(?<ui>[_$a-zA-Z0-9]+)/,
+    // `@uiEvent("optional` | `@uiEvent<T>("`
+    endsWithEventDecoratorElementName: () => /@uiEvent(\<.*\>)?\("[^"]*$/,
+    // @eventListener({ ... target: "optional
+    endsWithEventListenerDecoratorTarget: () => /@eventListener\({[^}]*target:\s*"[^"]*$/,
+  },
+  hbs: {
+    // `<some-tag class="className {{#if foo}}className2{{/if}}"`
+    classNamesAndTags: () => /<(?<tagName>[a-zA-Z0-9_-]+)[^>]*?(class="(?<className>[^"]*))?"/,
+    // {{#> some-partial
+    partials: () => /{{#?>\s*(?<partial>[-_a-zA-Z0-9]+)/g,
+  },
+};
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/server.ts b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
index bbb407ec..c6c10be5 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/server.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
@@ -15,8 +15,9 @@ import DiagnosticProvide from "./diagnosticProvider";
 import { definitionProvider } from "./definitionProvider";
 import { completionProvider } from "./completionProvider";
 import { hoverProvider } from "./hoverProvider";
-import { getFilePath } from "./helpers";
+import { getFilePath, isHandlebarsFile, isTypescriptFile } from "./helpers";
 import { codelensProvider } from "./codelensProvider";
+import { tsCompletionProvider } from "./tsCompletionProvider";
 
 // Create a connection for the server, using Node's IPC as a transport.
 // Also include all preview / proposed LSP features.
@@ -75,9 +76,11 @@ connection.onDidChangeConfiguration(_change => {
 
   // update diagnostics info for the open files
   openDocuments.forEach(async document => {
-    const settings = await SettingsService.getDocumentSettings(document.uri);
-    if (settings.validateHandlebars) DiagnosticProvide.setDiagnostics(document);
-    else DiagnosticProvide.unsetDiagnostics(document);
+    if (isHandlebarsFile(document.uri)) {
+      const settings = await SettingsService.getDocumentSettings(document.uri);
+      if (settings.validateHandlebars) DiagnosticProvide.setDiagnostics(document);
+      else DiagnosticProvide.unsetDiagnostics(document);
+    }
   });
 });
 
@@ -85,10 +88,15 @@ connection.onDidChangeConfiguration(_change => {
 connection.onCompletion(async (textDocumentPosition: TextDocumentPositionParams): Promise<CompletionItem[] | null> => {
   const document = documents.get(textDocumentPosition.textDocument.uri);
 
-  if (document) {
-    const filePath = getFilePath(document);
-    if (filePath) return completionProvider(document, textDocumentPosition.position, filePath);
-  }
+  if (!document) return null;
+
+  const filePath = getFilePath(document);
+  const settings = await SettingsService.getDocumentSettings(document.uri);
+
+  if (isHandlebarsFile(filePath)) return completionProvider(document, textDocumentPosition.position, filePath);
+  else if (isTypescriptFile(filePath) && settings.provideUiCompletionInTypescript)
+    return tsCompletionProvider(document, textDocumentPosition.position, filePath);
+
   return null;
 });
 
@@ -96,7 +104,7 @@ connection.onHover(async ({ textDocument, position }) => {
   const document = documents.get(textDocument.uri);
   const settings = await SettingsService.getDocumentSettings(textDocument.uri);
 
-  if (document && settings.showHoverInfo) return hoverProvider(document, position);
+  if (document && settings.showHoverInfo && isHandlebarsFile(textDocument.uri)) return hoverProvider(document, position);
 
   return null;
 });
@@ -106,7 +114,7 @@ connection.onDefinition(({ textDocument, position }) => {
 
   if (document) {
     const filePath = getFilePath(document);
-    if (filePath) return definitionProvider(document, position, filePath);
+    if (isHandlebarsFile(filePath)) return definitionProvider(document, position, filePath);
   }
 
   return null;
@@ -116,21 +124,26 @@ connection.onCodeLens(async ({ textDocument }) => {
   const document = documents.get(textDocument.uri);
   const settings = await SettingsService.getDocumentSettings(textDocument.uri);
 
-  if (document && settings.showUIAndEvents) return codelensProvider(document);
+  if (document && settings.showUIAndEvents && isHandlebarsFile(textDocument.uri)) return codelensProvider(document);
 });
 
 // is called when the file is first opened and every time it is modified
 // only supporting push diagnostics
 documents.onDidChangeContent(change => {
   const document = change.document;
-  DiagnosticProvide.setDiagnostics(document);
-  openDocuments.add(document);
+  if (isHandlebarsFile(document.uri)) {
+    DiagnosticProvide.setDiagnostics(document);
+    openDocuments.add(document);
+  }
 });
 
 // a document has closed: clear all diagnostics
 documents.onDidClose(event => {
-  DiagnosticProvide.unsetDiagnostics(event.document);
-  openDocuments.delete(event.document);
+  const document = event.document;
+  if (isHandlebarsFile(document.uri)) {
+    DiagnosticProvide.unsetDiagnostics(document);
+    openDocuments.delete(document);
+  }
 });
 
 // Make the text document manager listen on the connection
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/tsCompletionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/tsCompletionProvider.ts
new file mode 100644
index 00000000..116d8fb0
--- /dev/null
+++ b/packages/vscode-pv-handlebars-language-server/server/src/tsCompletionProvider.ts
@@ -0,0 +1,90 @@
+import { CompletionItem, CompletionItemKind, Position } from "vscode-languageserver/node";
+import type { TextDocument } from "vscode-languageserver-textdocument";
+
+import { basename, getCssClasses } from "./helpers";
+import rgx from "./rgx";
+
+// finds all the class properties that have kluntje's `@uiElements` decorator
+async function getUIProperties(fileContent: string) {
+  const regex = new RegExp(rgx.ts.uiDecoratorPropertyName(), "g");
+  const uis: string[] = [];
+
+  let matches;
+  while ((matches = regex.exec(fileContent)) !== null) {
+    uis.push(matches.groups!.ui);
+  }
+
+  return uis;
+}
+
+/**
+ * provide completion suggestion for the current position in the handlebars file
+ * @param {TextDocument} document - current document
+ * @param {Position} position - current position
+ * @param {string} filePath - absolute unix path to the current document
+ * @returns {Promise<CompletionItem[] | null>}
+ */
+export async function tsCompletionProvider(
+  document: TextDocument,
+  position: Position,
+  filePath: string,
+): Promise<CompletionItem[] | null> {
+  const offset = document.offsetAt(position);
+  const originalText = document.getText();
+  // the file content from beginning till the current cursor position
+  let text = originalText.slice(0, offset);
+
+  // `@uiElement("` and `@uiElements("`
+  if (rgx.ts.endsWithUiDecoratorSelector().test(text)) {
+    const cssClasses = await getCssClasses(filePath);
+    const classes = Array.from(new Set(cssClasses.map(({ className }) => className)));
+    return classes.map(className => ({
+      label: "." + className,
+      kind: CompletionItemKind.Value,
+      insertText: text.endsWith(".") ? className : `.${className}`,
+      // start the list with css classes belonging to the same component
+      sortText: `${className.startsWith(basename(filePath)) ? "00" : ""}${className}`,
+    }));
+  }
+  // @uiEvent<T>()
+  else if (rgx.ts.endsWithEventDecoratorElementName().test(text)) {
+    const uis = await getUIProperties(originalText);
+    return uis.map(ui => ({
+      label: ui,
+      kind: CompletionItemKind.Value,
+    }));
+  }
+  // @eventListener({ ... target: "
+  else if (rgx.ts.endsWithEventListenerDecoratorTarget().test(text)) {
+    const suggestions = [];
+    // only when user hasent used "." before. otherwise obviosuly they are using some classes and that can't be mixed with ui references
+    if (!/"[^"]*\.[^"]*$/.test(text)) {
+      const uis = await getUIProperties(originalText);
+      suggestions.push(
+        ...uis.map(ui => ({
+          label: ui,
+          kind: CompletionItemKind.Value,
+          // start the list with uiElements
+          sortText: `00${ui}`,
+        })),
+      );
+    }
+
+    const cssClasses = await getCssClasses(filePath);
+    const classes = Array.from(new Set(cssClasses.map(({ className }) => className)));
+    suggestions.push(
+      ...classes.map(className => ({
+        label: "." + className,
+        kind: CompletionItemKind.Value,
+        insertText: text.endsWith(".") ? className : `.${className}`,
+        // continue the list with css classes belonging to the same component
+        // and the the end any other css (e.g. grid, helpers, etc)
+        sortText: `${className.startsWith(basename(filePath)) ? "11" : ""}${className}`,
+      })),
+    );
+
+    return suggestions;
+  }
+
+  return null;
+}
diff --git a/packages/vscode-pv-handlebars-language-server/server/tsconfig.json b/packages/vscode-pv-handlebars-language-server/server/tsconfig.json
index c815e7fb..9f961995 100644
--- a/packages/vscode-pv-handlebars-language-server/server/tsconfig.json
+++ b/packages/vscode-pv-handlebars-language-server/server/tsconfig.json
@@ -1,7 +1,7 @@
 {
   "compilerOptions": {
-    "target": "es2019",
-    "lib": ["ES2019"],
+    "target": "ESNext",
+    "lib": ["ESNext"],
     "module": "commonjs",
     "moduleResolution": "node",
     "sourceMap": true,
diff --git a/packages/vscode-pv-handlebars-language-server/tsconfig.json b/packages/vscode-pv-handlebars-language-server/tsconfig.json
index 139853b9..41b1e060 100644
--- a/packages/vscode-pv-handlebars-language-server/tsconfig.json
+++ b/packages/vscode-pv-handlebars-language-server/tsconfig.json
@@ -1,8 +1,8 @@
 {
 	"compilerOptions": {
 		"module": "commonjs",
-		"target": "es2019",
-		"lib": ["ES2019"],
+		"target": "ESNext",
+		"lib": ["ESNext"],
 		"outDir": "out",
 		"rootDir": "src",
 		"sourceMap": true

From e18d7440fc943dc47ffad038b419ed90075b658a Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Fri, 21 Jun 2024 15:54:45 +0200
Subject: [PATCH 4/7] feat(vscode-pv-handlebars-language-server): add goto
 definition support for ui prop/selectors in TS

---
 .../package.json                              |  4 +-
 .../server/src/SettingsService.ts             |  8 +--
 .../server/src/codelensProvider.ts            | 23 +++++---
 .../server/src/helpers.ts                     | 58 +++++++++++++------
 .../server/src/rgx.ts                         |  6 +-
 .../server/src/server.ts                      | 28 ++++-----
 .../server/src/tsDefinitionProvider.ts        | 52 +++++++++++++++++
 7 files changed, 133 insertions(+), 46 deletions(-)
 create mode 100644 packages/vscode-pv-handlebars-language-server/server/src/tsDefinitionProvider.ts

diff --git a/packages/vscode-pv-handlebars-language-server/package.json b/packages/vscode-pv-handlebars-language-server/package.json
index b535aaf3..5c66fb4b 100644
--- a/packages/vscode-pv-handlebars-language-server/package.json
+++ b/packages/vscode-pv-handlebars-language-server/package.json
@@ -58,13 +58,13 @@
           "default": true,
           "description": "Marks any parse issue in the handlebars files."
         },
-        "P!VHandlebarsLanguageServer.showUIAndEvents": {
+        "P!VHandlebarsLanguageServer.showUiAndEvents": {
           "scope": "window",
           "type": "boolean",
           "default": true,
           "description": "Show ui and event info for html elements used by the kluntje custom elements in the hbs files."
         },
-        "P!VHandlebarsLanguageServer.provideUiCompletionInTypescript": {
+        "P!VHandlebarsLanguageServer.provideUiSupportInTypescript": {
           "scope": "window",
           "type": "boolean",
           "default": true,
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
index eab78690..e854a613 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/SettingsService.ts
@@ -6,12 +6,12 @@ interface Settings {
   provideCssClassGoToDefinition: boolean;
   provideCssClassCompletion: boolean;
   validateHandlebars: boolean;
-  showUIAndEvents: boolean;
-  provideUiCompletionInTypescript: boolean;
+  showUiAndEvents: boolean;
+  provideUiSupportInTypescript: boolean;
 }
 
 // singleton class to return users extension settings
-export default new class SettingsService {
+export default new (class SettingsService {
   connection?: Connection;
 
   // cache the settings of all open documents
@@ -49,4 +49,4 @@ export default new class SettingsService {
     // Reset all cached document settings
     this.documentSettings.clear();
   }
-}();
+})();
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
index 61b85b19..b4c3bc39 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
@@ -6,7 +6,6 @@ import { getCustomElementsUIAndEvents } from "./customElementDefinitionProvider"
 import { getFilePath } from "./helpers";
 import rgx from "./rgx";
 
-
 /**
  * creates an object that can be consumed by onCodeLens request handler (see vscode's `CodeLens` interface for more info)
  *
@@ -54,16 +53,26 @@ export async function codelensProvider(textDocument: TextDocument) {
   if (!selectors) return null;
 
   const content = textDocument.getText();
-  const regex = new RegExp(rgx.hbs.classNamesAndTags(), "g");
-  let matches;
+  // supporting ui selector being a css class, or a tag name for now
+  const matches = [
+    ...content.matchAll(new RegExp(rgx.hbs.tags(), "g")),
+    ...content.matchAll(new RegExp(rgx.hbs.classNames(), "g")),
+  ];
 
-  while ((matches = regex.exec(content)) !== null) {
+  for (const match of matches) {
     for (const [selector, item] of Object.entries(selectors)) {
       const classMatch =
-        selector.startsWith(".") && matches.groups!.className?.split(" ").includes(selector.replace(/^./, ""));
-      const tagMatch = matches.groups!.tagName === selector;
+        selector.startsWith(".") &&
+        match
+          // remove handlebar expressions
+          .groups!.className?.replaceAll(/{{.*?}}/g, "")
+          // split each css class
+          .split(" ")
+          // check if one is the same as the ui selector
+          .includes(selector.replace(/^./, ""));
+      const tagMatch = match.groups!.tagName === selector;
       if (classMatch || tagMatch) {
-        const line = content.substring(0, matches.index).split("\n").length - 1;
+        const line = content.substring(0, match.index).split("\n").length - 1;
 
         if (item.ui) {
           codeLenses.push(
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
index 908fd393..99841eaa 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
@@ -311,29 +311,33 @@ export async function getCssClasses(filePath: string) {
 
   for (const hbsFile of templates) {
     const fileContent = hbsFile.fileContent;
-    const regex = new RegExp(rgx.hbs.classNamesAndTags(), "g");
-    let matches;
-    while ((matches = regex.exec(fileContent)) !== null) {
-      if (!matches.groups!.className) continue;
-
-      const contentBefore = fileContent.substring(0, matches.index);
-      const line = contentBefore.split("\n").length - 1;
-      const character = matches.index - contentBefore.lastIndexOf("\n");
-      let className = matches.groups!.className;
+    const matches = Array.from(fileContent.matchAll(new RegExp(rgx.hbs.classNames(), "g")));
+    for (const match of matches) {
+      let className = match.groups!.className;
       className = className.replace(/{{.*?}}/g, "");
+
       const classes = className
         .split(" ")
         .map(c => c.trim())
         .filter(c => c !== "");
+
       cssClasses.push(
-        ...classes.map(clss => ({
-          className: clss,
-          location: {
-            filePath,
-            line,
-            character,
-          },
-        })),
+        ...classes.map(clss => {
+          const start = getPositionAt(fileContent, match!.index + match![0].indexOf(clss));
+          return {
+            className: clss,
+            location: {
+              filePath: hbsFile.filePath,
+              range: {
+                start: start,
+                end: {
+                  line: start.line,
+                  character: start.character + clss.length,
+                },
+              },
+            },
+          };
+        }),
       );
     }
   }
@@ -358,6 +362,7 @@ export async function getNestedTemplates(hbsTemplate: string) {
       }
     } else if (!visited.includes(filePaths)) {
       visited.push(filePaths);
+
       const fileContent = await getFileContent(filePaths);
       results.push({ filePath: filePaths, fileContent });
 
@@ -381,3 +386,22 @@ export async function getNestedTemplates(hbsTemplate: string) {
 
   return searchRecursive(hbsTemplate);
 }
+
+/**
+ * Converts a zero-based offset to a position (line, character).
+ *
+ * @param {text} text
+ * @param {number} offset
+ * @returns {line: number, character: number}
+ */
+export function getPositionAt(text: string, offset: number) {
+  const textBefore = text.substring(0, offset);
+  const lines = textBefore.split("\n");
+  const line = lines.length - 1;
+  const character = lines.at(-1)!.length;
+
+  return {
+    line,
+    character,
+  };
+}
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts b/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts
index 0938af28..84bbad14 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/rgx.ts
@@ -10,8 +10,10 @@ export default {
     endsWithEventListenerDecoratorTarget: () => /@eventListener\({[^}]*target:\s*"[^"]*$/,
   },
   hbs: {
-    // `<some-tag class="className {{#if foo}}className2{{/if}}"`
-    classNamesAndTags: () => /<(?<tagName>[a-zA-Z0-9_-]+)[^>]*?(class="(?<className>[^"]*))?"/,
+    // `<some-tag`
+    tags: () => /<(?<tagName>[a-zA-Z0-9_-]+)/,
+    // `<some-tag ... class="className {{...}}className2"`
+    classNames: () => /<(?<tagName>[a-zA-Z0-9_-]+)[^>]*?class="(?<className>[^"]*)"/,
     // {{#> some-partial
     partials: () => /{{#?>\s*(?<partial>[-_a-zA-Z0-9]+)/g,
   },
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/server.ts b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
index c6c10be5..b9066297 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/server.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/server.ts
@@ -18,6 +18,7 @@ import { hoverProvider } from "./hoverProvider";
 import { getFilePath, isHandlebarsFile, isTypescriptFile } from "./helpers";
 import { codelensProvider } from "./codelensProvider";
 import { tsCompletionProvider } from "./tsCompletionProvider";
+import { tsDefinitionProvider } from "./tsDefinitionProvider";
 
 // Create a connection for the server, using Node's IPC as a transport.
 // Also include all preview / proposed LSP features.
@@ -86,45 +87,44 @@ connection.onDidChangeConfiguration(_change => {
 
 // This handler provides the initial list of the completion items.
 connection.onCompletion(async (textDocumentPosition: TextDocumentPositionParams): Promise<CompletionItem[] | null> => {
-  const document = documents.get(textDocumentPosition.textDocument.uri);
-
-  if (!document) return null;
+  const document = documents.get(textDocumentPosition.textDocument.uri)!;
 
   const filePath = getFilePath(document);
   const settings = await SettingsService.getDocumentSettings(document.uri);
 
   if (isHandlebarsFile(filePath)) return completionProvider(document, textDocumentPosition.position, filePath);
-  else if (isTypescriptFile(filePath) && settings.provideUiCompletionInTypescript)
+  else if (isTypescriptFile(filePath) && settings.provideUiSupportInTypescript)
     return tsCompletionProvider(document, textDocumentPosition.position, filePath);
 
   return null;
 });
 
 connection.onHover(async ({ textDocument, position }) => {
-  const document = documents.get(textDocument.uri);
+  const document = documents.get(textDocument.uri)!;
   const settings = await SettingsService.getDocumentSettings(textDocument.uri);
 
-  if (document && settings.showHoverInfo && isHandlebarsFile(textDocument.uri)) return hoverProvider(document, position);
+  if (settings.showHoverInfo && isHandlebarsFile(textDocument.uri)) return hoverProvider(document, position);
 
   return null;
 });
 
-connection.onDefinition(({ textDocument, position }) => {
-  const document = documents.get(textDocument.uri);
+connection.onDefinition(async ({ textDocument, position }) => {
+  const document = documents.get(textDocument.uri)!;
+  const settings = await SettingsService.getDocumentSettings(document.uri);
+  const filePath = getFilePath(document);
 
-  if (document) {
-    const filePath = getFilePath(document);
-    if (isHandlebarsFile(filePath)) return definitionProvider(document, position, filePath);
-  }
+  if (isHandlebarsFile(filePath)) return definitionProvider(document, position, filePath);
+  else if (isTypescriptFile(filePath) && settings.provideUiSupportInTypescript)
+    return tsDefinitionProvider(document, position, filePath);
 
   return null;
 });
 
 connection.onCodeLens(async ({ textDocument }) => {
-  const document = documents.get(textDocument.uri);
+  const document = documents.get(textDocument.uri)!;
   const settings = await SettingsService.getDocumentSettings(textDocument.uri);
 
-  if (document && settings.showUIAndEvents && isHandlebarsFile(textDocument.uri)) return codelensProvider(document);
+  if (settings.showUiAndEvents && isHandlebarsFile(textDocument.uri)) return codelensProvider(document);
 });
 
 // is called when the file is first opened and every time it is modified
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/tsDefinitionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/tsDefinitionProvider.ts
new file mode 100644
index 00000000..1c774616
--- /dev/null
+++ b/packages/vscode-pv-handlebars-language-server/server/src/tsDefinitionProvider.ts
@@ -0,0 +1,52 @@
+import { Location, Position } from "vscode-languageserver/node";
+import { TextDocument } from "vscode-languageserver-textdocument";
+import { URI } from "vscode-uri";
+import { isPVArchetype, getCurrentSymbolsName, getCssClasses, getPositionAt } from "./helpers";
+import rgx from "./rgx";
+
+export async function tsDefinitionProvider(
+  document: TextDocument,
+  position: Position,
+  filePath: string,
+): Promise<Location | Location[] | null> {
+  // simple check if it is a component ala p!v archetype
+  if (!isPVArchetype(filePath)) return null;
+
+  const offset = document.offsetAt(position);
+  const originalText = document.getText();
+  const textBefore = originalText.slice(0, offset);
+
+  const symbolName = getCurrentSymbolsName(document, position);
+  // `.some-selector` and not `uiProp`
+  const isCssClassSelector = /\.[a-zA-Z_-]+$/.test(textBefore);
+
+  // `@uiElement("` and `@uiElements("` or `// @eventListener({ ... target: ".class`
+  if (
+    rgx.ts.endsWithUiDecoratorSelector().test(textBefore) ||
+    (rgx.ts.endsWithEventListenerDecoratorTarget().test(textBefore) && isCssClassSelector)
+  ) {
+    const cssClasses = await getCssClasses(filePath);
+    return cssClasses
+      .filter(cssClass => cssClass.className === symbolName)
+      .map(cssClass => Location.create(URI.file(cssClass.location.filePath).toString(), cssClass.location.range));
+  }
+  // `@uiEvent("uiProp` or `@eventListener({ ... target: "uiProp`
+  else if (
+    rgx.ts.endsWithEventDecoratorElementName().test(textBefore) ||
+    (rgx.ts.endsWithEventListenerDecoratorTarget().test(textBefore) && !isCssClassSelector)
+  ) {
+    const uiMatch = originalText.match(new RegExp(`@uiElements?\\(.+?\\)\\s*${symbolName}`));
+    if (uiMatch) {
+      const deco = uiMatch[0].match(/@uiElements?\(.+?\)\s*/)![0];
+      const start = getPositionAt(originalText, uiMatch.index! + deco.length);
+      return Location.create(document.uri, {
+        start,
+        end: {
+          line: start.line,
+          character: start.character + symbolName.length,
+        },
+      });
+    }
+  }
+  return null;
+}

From 9c5a8fbfbb96baca0d663befcd8833c363d2aca9 Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Tue, 25 Jun 2024 11:28:53 +0200
Subject: [PATCH 5/7] fix(vscode-pv-handlebars-language-server): add better
 support for layout option in the templates

---
 .../server/src/completionProvider.ts          |  2 +-
 .../server/src/definitionProvider.ts          | 33 ++++++++++++++-----
 .../server/src/helpers.ts                     | 18 +++++++---
 3 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/packages/vscode-pv-handlebars-language-server/server/src/completionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/completionProvider.ts
index 9735aca5..9317833a 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/completionProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/completionProvider.ts
@@ -204,7 +204,7 @@ export async function completionProvider(
   if (/^\n*---[^---]*layout:\s*(\w|\d)*$/.test(text)) {
     const isPageTemplate = filePath.includes("/frontend/src/pages");
     const layouts = await getLayoutFiles(componentsRootPath);
-    const relevantLayouts = layouts?.[isPageTemplate ? "pages" : "lsg"];
+    const relevantLayouts = isPageTemplate ? layouts?.normal : {...layouts?.normal , ...layouts?.lsg};
 
     if (relevantLayouts)
       return Object.keys(relevantLayouts)
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
index 6b170759..e7e82b38 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
@@ -58,8 +58,8 @@ export async function definitionProvider(
   const componentsRootPath = filePath.includes("src/components/")
     ? `${filePath.split("/frontend/src/components")[0]}/frontend/src/components`
     : filePath.includes("src/pages/")
-      ? `${filePath.split("/frontend/src/pages")[0]}/frontend/src/components`
-      : `${filePath.split("/frontend/src/layouts")[0]}/frontend/src/components`;
+    ? `${filePath.split("/frontend/src/pages")[0]}/frontend/src/components`
+    : `${filePath.split("/frontend/src/layouts")[0]}/frontend/src/components`;
 
   // e.g. {{> partial
   if (isPartial(textBefore)) {
@@ -149,12 +149,23 @@ export async function definitionProvider(
    ---
   */
   else if (/^\n*---[^---]*layout:\s*(\w|\d)+$/.test(textBefore)) {
-    // templates inside /page/ directory use different layouts than the open under /components/
+    // templates inside /components/ directory in the older assemble/stylemark were rendered with the layout hbs files *and a second time* with the `lsgTemplatesSrc` layouts
+    // these option doesn't need to be shown for /pages/
     const isPageTemplate = filePath.includes("/frontend/src/pages");
-    const layouts = await getLayoutFiles(componentsRootPath);
-    const layoutFilePath = layouts?.[isPageTemplate ? "pages" : "lsg"]?.[symbolName];
+    const allLayouts = await getLayoutFiles(componentsRootPath);
+    if (!allLayouts) return null;
+
+    const normalLayouts = allLayouts.normal;
+    const lsgLayouts = allLayouts.lsg;
+
+    const layouts = [];
+    if (normalLayouts) layouts.push(...Object.entries(normalLayouts));
+    if (lsgLayouts && !isPageTemplate) layouts.push(...Object.entries(lsgLayouts));
+    const results = [];
+
+    for (const [name, layoutFilePath] of layouts) {
+      if (name !== symbolName) continue;
 
-    if (layoutFilePath) {
       const fileContent = await getFileContent(layoutFilePath);
       // placeholder assemble-lite uses to place content in the layout
       const BODY_PLACEHOLDER = "{% body%}";
@@ -164,14 +175,18 @@ export async function definitionProvider(
       if (placeholderStart !== -1) {
         const before = fileContent.slice(0, placeholderStart);
         const lineNumber = (before.match(/\n/g) || []).length;
-        return Location.create(URI.file(layoutFilePath).toString(), Range.create(lineNumber, 0, lineNumber, 1000));
+        results.push(
+          Location.create(URI.file(layoutFilePath).toString(), Range.create(lineNumber, 0, lineNumber, 1000)),
+        );
       }
       // whole file
       else {
-        return Location.create(URI.file(layoutFilePath).toString(), Range.create(0, 0, 0, 0));
+        results.push(Location.create(URI.file(layoutFilePath).toString(), Range.create(0, 0, 0, 0)));
       }
-
     }
+
+    return results;
   }
+
   return null;
 }
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
index 99841eaa..c6c5da05 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
@@ -11,6 +11,10 @@ import rgx from "./rgx";
 interface PVConfig {
   hbsHelperSrc?: string;
   namespace?: string;
+  /**
+   * @deprecated
+   * was removed in pv-stylemark v4.
+   */
   lsgTemplatesSrc?: string;
   cdTemplatesSrc?: string;
 }
@@ -161,8 +165,13 @@ export async function getCustomHelperFiles(componentsRootPath: string): Promise<
 }
 
 interface LayoutFiles {
-  lsg?: { [name: string]: string };
-  pages?: { [name: string]: string };
+  // list of layouts only used to generate lsg_components
+  lsg?: {
+    // e.g. default: "/lsg/layouts/default.hbs"
+    [name: string]: string;
+  };
+  // layouts to generate pages/ and components/
+  normal?: { [name: string]: string };
 }
 
 // list of hbs files which are used in assemble-lite as layouts for lsg components or pages
@@ -172,13 +181,14 @@ export async function getLayoutFiles(componentsRootPath: string): Promise<Layout
 
   if (pvConfig === null) return null;
 
-  const layouts: Array<{ name: "lsg" | "pages"; dir: string | undefined }> = [
+  const layouts: Array<{ name: "lsg" | "normal"; dir: string | undefined }> = [
+    // still provide backwards compatibility for projects not yet migrated to the new pv-stylemark
     {
       name: "lsg",
       dir: pvConfig.lsgTemplatesSrc,
     },
     {
-      name: "pages",
+      name: "normal",
       dir: pvConfig.cdTemplatesSrc,
     },
   ];

From e439f775deca13c8262257bc0e7b87b2dd36ca86 Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Tue, 25 Jun 2024 15:09:03 +0200
Subject: [PATCH 6/7] feat(vscode-pv-handlebars-language-server): support
 assemble layout files being placed in /templates/ instead of /layouts/

---
 .../server/src/definitionProvider.ts                          | 4 +++-
 .../server/src/helpers.ts                                     | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
index e7e82b38..a5f14e5d 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/definitionProvider.ts
@@ -59,7 +59,9 @@ export async function definitionProvider(
     ? `${filePath.split("/frontend/src/components")[0]}/frontend/src/components`
     : filePath.includes("src/pages/")
     ? `${filePath.split("/frontend/src/pages")[0]}/frontend/src/components`
-    : `${filePath.split("/frontend/src/layouts")[0]}/frontend/src/components`;
+    : filePath.includes("src/layouts/")
+    ? `${filePath.split("/frontend/src/layouts")[0]}/frontend/src/components`
+    : `${filePath.split("/frontend/src/templates")[0]}/frontend/src/components`;
 
   // e.g. {{> partial
   if (isPartial(textBefore)) {
diff --git a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
index c6c5da05..6b1c3a1a 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/helpers.ts
@@ -77,7 +77,8 @@ export function isPVArchetype(templatePath: string): boolean {
   return (
     templatePath.includes("/frontend/src/components") ||
     templatePath.includes("/frontend/src/pages") ||
-    templatePath.includes("/frontend/src/layouts")
+    templatePath.includes("/frontend/src/layouts") ||
+    templatePath.includes("/frontend/src/templates")
   );
 }
 

From 281d93af53de6e7a26899e37cf6db89cbf67e6f4 Mon Sep 17 00:00:00 2001
From: mbehzad <mehran.behzad@diva-e.com>
Date: Thu, 12 Sep 2024 16:09:09 +0200
Subject: [PATCH 7/7] fix(vscode-pv-handlebars-language-server): add support
 for ui and events info

fix duplicate reports when the tag matched
---
 .../server/src/codelensProvider.ts                            | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
index b4c3bc39..b31ff5d2 100644
--- a/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
+++ b/packages/vscode-pv-handlebars-language-server/server/src/codelensProvider.ts
@@ -70,7 +70,9 @@ export async function codelensProvider(textDocument: TextDocument) {
           .split(" ")
           // check if one is the same as the ui selector
           .includes(selector.replace(/^./, ""));
-      const tagMatch = match.groups!.tagName === selector;
+
+      // ignore the tag matches for the classNames rgx because it is already catch by the tags rgx already.
+      const tagMatch = !("className" in match.groups!) && match.groups!.tagName === selector;
       if (classMatch || tagMatch) {
         const line = content.substring(0, match.index).split("\n").length - 1;