From dac0a80d470e7c435d497fc0a6edd5cd297ee57c Mon Sep 17 00:00:00 2001
From: ewin <git@ewin.moe>
Date: Mon, 10 Mar 2025 00:02:54 -0400
Subject: [PATCH] hey look a thing

---
 .gitignore                             |   2 +
 .vscode/launch.json                    |  17 +
 README.md                              |   3 +
 base.package.json                      |  22 +
 build.mts                              |  14 +
 dprint.json                            |  39 ++
 embeddedLanguages.mts                  |  34 ++
 grammar.mts                            |  40 ++
 package-lock.json                      | 569 +++++++++++++++++++++++++
 package.json.mts                       |  35 ++
 syntaxes/javascript.injection.json.mts |  40 ++
 util.mts                               |  10 +
 12 files changed, 825 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 .vscode/launch.json
 create mode 100644 README.md
 create mode 100644 base.package.json
 create mode 100755 build.mts
 create mode 100644 dprint.json
 create mode 100644 embeddedLanguages.mts
 create mode 100644 grammar.mts
 create mode 100644 package-lock.json
 create mode 100644 package.json.mts
 create mode 100644 syntaxes/javascript.injection.json.mts
 create mode 100644 util.mts

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..67dfeb3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+*.vsix
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..44a86ab
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,17 @@
+// A launch configuration that launches the extension inside a new window
+// Use IntelliSense to learn about possible attributes.
+// Hover to view descriptions of existing attributes.
+// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+{
+	"version": "0.2.0",
+	"configurations": [
+		{
+			"name": "Extension",
+			"type": "extensionHost",
+			"request": "launch",
+			"args": [
+				"--extensionDevelopmentPath=${workspaceFolder}"
+			]
+		}
+	]
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..daf70ff
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# embedded-string-highlighting
+
+> textmate grammars can't be *that* bad right??
diff --git a/base.package.json b/base.package.json
new file mode 100644
index 0000000..82a5641
--- /dev/null
+++ b/base.package.json
@@ -0,0 +1,22 @@
+{
+	"name": "embedded-string-highlighting",
+	"displayName": "fuck fuck fuck",
+	"description": "yeet",
+	"version": "0.0.1",
+	"engines": {
+		"vscode": "^1.98.0"
+	},
+	"categories": [
+		"Programming Languages"
+	],
+	"scripts": {
+		"build": "node build.mjs",
+		"build:watch": "nodemon -e js,mjs,cjs --exec npm run build"
+	},
+	"devDependencies": {
+		"dprint": "^0.49.0",
+		"js-yaml": "^4.1.0",
+		"nodemon": "^3.1.9",
+		"vscode-textmate": "^9.2.0"
+	}
+}
diff --git a/build.mts b/build.mts
new file mode 100755
index 0000000..0e902b4
--- /dev/null
+++ b/build.mts
@@ -0,0 +1,14 @@
+#!/usr/bin/env node
+
+import {glob, writeFile} from 'node:fs/promises';
+
+for await (const input of glob('./**/*.json.{js,mjs,ts,mts}')) {
+	(async () => {
+		const m = await import(`./${input}`);
+		await writeFile(
+			input.replace(/\.json\..*$/, '.json'),
+			JSON.stringify(m.default, null, '\t'),
+			{encoding: 'utf-8'},
+		);
+	})();
+}
diff --git a/dprint.json b/dprint.json
new file mode 100644
index 0000000..850ef7c
--- /dev/null
+++ b/dprint.json
@@ -0,0 +1,39 @@
+{
+	"typescript": {
+		"lineWidth": 80,
+		"indentWidth": 4,
+		"useTabs": true,
+		"quoteStyle": "alwaysSingle",
+		"quoteProps": "consistent",
+		"useBraces": "always",
+		"arrowFunction.useParentheses": "preferNone",
+		"enumDeclaration.memberSpacing": "newLine",
+		"spaceSurroundingProperties": false,
+		"exportDeclaration.spaceSurroundingNamedExports": false,
+		"importDeclaration.spaceSurroundingNamedImports": false,
+		"constructor.spaceBeforeParentheses": true,
+		"functionDeclaration.spaceBeforeParentheses": true,
+		"functionExpression.spaceBeforeParentheses": true,
+		"getAccessor.spaceBeforeParentheses": true,
+		"setAccessor.spaceBeforeParentheses": true,
+		"method.spaceBeforeParentheses": true
+	},
+	"json": {
+		"indentWidth": 4,
+		"useTabs": true
+	},
+	"markdown": {
+		"emphasisKind": "asterisks",
+		"strongKind": "asterisks"
+	},
+	"excludes": [
+		"**/node_modules",
+		"**/*-lock.json",
+		"dist"
+	],
+	"plugins": [
+		"https://plugins.dprint.dev/typescript-0.93.3.wasm",
+		"https://plugins.dprint.dev/json-0.19.4.wasm",
+		"https://plugins.dprint.dev/markdown-0.17.8.wasm"
+	]
+}
diff --git a/embeddedLanguages.mts b/embeddedLanguages.mts
new file mode 100644
index 0000000..4b47992
--- /dev/null
+++ b/embeddedLanguages.mts
@@ -0,0 +1,34 @@
+import packageJSON from './base.package.json';
+
+const languages: {
+	id: string;
+	sourceScope: string;
+	aliases?: string[];
+}[] = [
+	{id: 'javascript', sourceScope: 'source.js'},
+	{id: 'typescript', sourceScope: 'source.ts'},
+	{id: 'javascriptreact', sourceScope: 'source.js.jsx'},
+	{id: 'typescriptreact', sourceScope: 'source.tsx'},
+	{id: 'json', sourceScope: 'source.json'},
+	{id: 'jsonc', sourceScope: 'source.json.comments'},
+	{id: 'jsonl', sourceScope: 'source.json.lines'},
+	{id: 'shellscript', sourceScope: 'source.shell'},
+	{id: 'rust', sourceScope: 'source.rust'},
+	{id: 'css', sourceScope: 'source.css'},
+	{id: 'scss', sourceScope: 'source.css.scss'},
+	{id: 'less', sourceScope: 'source.css.less'},
+	{id: 'html', sourceScope: 'text.html.derivative'},
+	{id: 'sql', sourceScope: 'source.sql'},
+	{id: 'markdown', sourceScope: 'text.html.markdown'},
+	{id: 'xml', sourceScope: 'text.xml'},
+	{id: 'yaml', sourceScope: 'source.yaml'},
+];
+
+export default languages.map(language => ({
+	id: language.id,
+	tags: [language.id, ...(language.aliases ?? [])],
+	sourceScope: language.sourceScope,
+	embedScopeInline: `meta.embedded.inline.${language.id}`,
+	embedScopeBlock: `meta.embedded.block.${language.id}`,
+	injectionScope: `${packageJSON.name}.injection.${language.id}`,
+}));
diff --git a/grammar.mts b/grammar.mts
new file mode 100644
index 0000000..60a1898
--- /dev/null
+++ b/grammar.mts
@@ -0,0 +1,40 @@
+import {IRawGrammar} from 'vscode-textmate';
+
+// vscode-textmate doesn't expose anything else so fine we'll do it ourselves
+
+type AllOptionalWritable<T> = { -readonly [K in keyof T]?: T[K] };
+export type Overwrite<T, U> = {
+	[K in keyof (T & U)]: K extends keyof U ? U[K]
+		: K extends keyof T ? T[K]
+		: never;
+};
+type RemoveLocation<T> = Omit<T, '$vscodeTextmateLocation'>;
+
+type Cleanup<T, Overrides = unknown> = AllOptionalWritable<
+	RemoveLocation<Overwrite<T, Overrides>>
+>;
+
+type IRawRepository = IRawGrammar['repository'];
+type IRawRule = IRawRepository[string];
+type IRawCaptures = NonNullable<IRawRule['captures']>;
+
+export type Captures = Cleanup<IRawCaptures>;
+export type Rule = Cleanup<IRawRule, {
+	captures: Captures;
+	beginCaptures: Captures;
+	endCaptures: Captures;
+	whileCaptures: Captures;
+	repository: Repository;
+}>;
+export type Repository = Cleanup<IRawRepository, {
+	[name: string]: Rule;
+	$self: Rule;
+	$base: Rule;
+}>;
+export type Grammar = Cleanup<IRawGrammar, {
+	repository: Repository;
+	patterns: Rule[];
+	injections: {
+		[expression: string]: Rule;
+	};
+}>;
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..5089a91
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,569 @@
+{
+  "name": "embedded-string-highlighting",
+  "version": "0.0.1",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "embedded-string-highlighting",
+      "version": "0.0.1",
+      "devDependencies": {
+        "dprint": "^0.49.0",
+        "js-yaml": "^4.1.0",
+        "nodemon": "^3.1.9",
+        "vscode-textmate": "^9.2.0"
+      },
+      "engines": {
+        "vscode": "^1.98.0"
+      }
+    },
+    "node_modules/@dprint/darwin-arm64": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.49.0.tgz",
+      "integrity": "sha512-b8fwjdfYrX5H+QyeWiB27gPc1GMVdd2LorCtsZWC+MDQO6NOgpuxJePqccbQlFUumy2rfmQuLQprnldvQZhceg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@dprint/darwin-x64": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.49.0.tgz",
+      "integrity": "sha512-cA/DIPlHClkufLufuIfcXHtZdlyP9U05RuJLvvAfHwJAxyeEC/chKYVc5BVz86RxMIq6czFGpJHoFtTjrfM3YA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@dprint/linux-arm64-glibc": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.49.0.tgz",
+      "integrity": "sha512-UBo3lDJhotT+qza2S48DOPI64MirkJMoFDidh/TJBjokio2TcGd+QUzuB9O7J1+R3AlbwyObcTECjJryCNohHQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@dprint/linux-arm64-musl": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.49.0.tgz",
+      "integrity": "sha512-XWAPL6Hp+zqk9bi57450wuy4yz4fvT72L3Zji3X7ChL5KD/apMUzQnZhmTpln2sxwIgJ3nCbzEzlF7jhhp/7KA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@dprint/linux-riscv64-glibc": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/linux-riscv64-glibc/-/linux-riscv64-glibc-0.49.0.tgz",
+      "integrity": "sha512-6GlGcauMeMbCCJ15OmAMkarouCifij9hb12Vz5UUZPevnutVoWRTQBPQLfllmd+9Znsp23fHnmzmykibdwj4Gw==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@dprint/linux-x64-glibc": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.49.0.tgz",
+      "integrity": "sha512-PJUM1G8L2xwF9R1s4/J6kf29S2sJ/sZGy3ah7g5Uj+oYkZq6SlMOrx3xqCXEkKSa0T6Xuc1bUBcJyrjEf36xiw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@dprint/linux-x64-musl": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.49.0.tgz",
+      "integrity": "sha512-+WIInBwbCXYmWZcYYmnD8HdcZj6q8ewy6mPpHH6SDMtWr6nrxzyIVLFr72XeiBoHnVsQFUhN+wv5Bm5NnpJtRw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@dprint/win32-arm64": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/win32-arm64/-/win32-arm64-0.49.0.tgz",
+      "integrity": "sha512-AteygrhmT7OXIgE/72REUfTPs/+qU0I1vhU379AYXgcWzOKy6Eeyi8lAt17oF7OmGT4IuyrKEDjpdTxhOWLsQw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@dprint/win32-x64": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.49.0.tgz",
+      "integrity": "sha512-8bE6P9T/32Gd+zMAkcwvUHzOLEMnbHEMgsgiKypYsdFTskpDz+y1GLJvMaxIFd2DB2tMx9TdBYuBQrJroTsMeQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "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,
+      "license": "Python-2.0"
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+      "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+      "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/debug": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/dprint": {
+      "version": "0.49.0",
+      "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.49.0.tgz",
+      "integrity": "sha512-xtBPZbPKWOOJH5al4h6rgzsGHuXpyK7TFJCQ5/TW8Z4zkcB9dfmPAh14/Yp5YZcB798D0liztXw+Nd7suzdzBQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "dprint": "bin.js"
+      },
+      "optionalDependencies": {
+        "@dprint/darwin-arm64": "0.49.0",
+        "@dprint/darwin-x64": "0.49.0",
+        "@dprint/linux-arm64-glibc": "0.49.0",
+        "@dprint/linux-arm64-musl": "0.49.0",
+        "@dprint/linux-riscv64-glibc": "0.49.0",
+        "@dprint/linux-x64-glibc": "0.49.0",
+        "@dprint/linux-x64-musl": "0.49.0",
+        "@dprint/win32-arm64": "0.49.0",
+        "@dprint/win32-x64": "0.49.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/ignore-by-default": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+      "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "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==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/nodemon": {
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
+      "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "chokidar": "^3.5.2",
+        "debug": "^4",
+        "ignore-by-default": "^1.0.1",
+        "minimatch": "^3.1.2",
+        "pstree.remy": "^1.1.8",
+        "semver": "^7.5.3",
+        "simple-update-notifier": "^2.0.0",
+        "supports-color": "^5.5.0",
+        "touch": "^3.1.0",
+        "undefsafe": "^2.0.5"
+      },
+      "bin": {
+        "nodemon": "bin/nodemon.js"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/nodemon"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pstree.remy": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+      "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+      "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/simple-update-notifier": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+      "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "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,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/touch": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+      "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "nodetouch": "bin/nodetouch.js"
+      }
+    },
+    "node_modules/undefsafe": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+      "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vscode-textmate": {
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-9.2.0.tgz",
+      "integrity": "sha512-rkvG4SraZQaPSN/5XjwKswdU0OP9MF28QjrYzUBbhb8QyG3ljB1Ky996m++jiI7KdiAP2CkBiQZd9pqEDTClqA==",
+      "dev": true,
+      "license": "MIT"
+    }
+  }
+}
diff --git a/package.json.mts b/package.json.mts
new file mode 100644
index 0000000..a6f773c
--- /dev/null
+++ b/package.json.mts
@@ -0,0 +1,35 @@
+import packageJSON from './base.package.json';
+import languages from './embeddedLanguages.mts';
+import {merge} from './util.mts';
+
+// All host languages embed the same set of embedded languages
+const embeddedLanguages = merge(
+	languages.map(embeddedLanguage => ({
+		[embeddedLanguage.embedScopeInline]: embeddedLanguage.id,
+		[embeddedLanguage.embedScopeBlock]: embeddedLanguage.id,
+	})),
+);
+
+export default {
+	...packageJSON,
+	name: 'embedded-string-highlighting',
+	displayName: 'fuck fuck fuck',
+	description: 'yeet',
+	version: '0.0.1',
+	engines: {
+		vscode: '^1.98.0',
+	},
+	categories: [
+		'Programming Languages',
+	],
+	contributes: {
+		grammars: [
+			{
+				path: './syntaxes/javascript.injection.json',
+				scopeName: 'embedded-string-highlighting.injection',
+				injectTo: ['source.js'],
+				embeddedLanguages,
+			},
+		],
+	},
+};
diff --git a/syntaxes/javascript.injection.json.mts b/syntaxes/javascript.injection.json.mts
new file mode 100644
index 0000000..686ade0
--- /dev/null
+++ b/syntaxes/javascript.injection.json.mts
@@ -0,0 +1,40 @@
+import embeddedLanguages from '../embeddedLanguages.mjs';
+import {merge} from '../util.mjs';
+
+const elements = merge(embeddedLanguages.map(embeddedLanguage => ({
+	[`tagged-template-literal-block-${embeddedLanguage.id}`]: {
+		begin: `(${embeddedLanguage.id})(\`)`,
+		end: '`',
+		beginCaptures: {
+			1: {
+				name:
+					'entity.name.function.tagged-template.js entity.name.embedded-language',
+			},
+			2: {
+				name:
+					'string.template.js punctuation.definition.string.template.begin.js punctuation.definition.embedded-source.begin',
+			},
+		},
+		endCaptures: {
+			0: {
+				name:
+					'string.template.js punctuation.definition.string.template.end.js punctuation.definition.embedded-source.end',
+			},
+		},
+		contentName: embeddedLanguage.embedScopeBlock,
+		patterns: [
+			{
+				include: embeddedLanguage.sourceScope,
+			},
+		],
+	},
+})));
+
+export default {
+	scopeName: 'embedded-string-highlighting.injection',
+	injectionSelector: 'L:source.js -string -comment',
+	repository: elements,
+	patterns: Object.keys(elements).map(ruleKey => ({
+		include: `#${ruleKey}`,
+	})),
+};
diff --git a/util.mts b/util.mts
new file mode 100644
index 0000000..bc4d781
--- /dev/null
+++ b/util.mts
@@ -0,0 +1,10 @@
+import {Overwrite} from './grammar.mts';
+
+type AllMerged<Objects extends any[]> = Objects extends
+	[infer T, infer U, ...infer Rest] ? AllMerged<[Overwrite<T, U>, ...Rest]>
+	: Objects extends [infer T, ...infer Rest] ? T
+	: Objects extends (infer Rest)[] ? Rest
+	: never;
+
+export const merge = <T extends any[]>(objects: T): AllMerged<T> =>
+	Object.assign(Object.create(null), ...objects);