From 9e180c518d4a548226c04c817715c08012d1c9db Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 02:07:26 +0900 Subject: [PATCH 01/18] fix: fix error with `` component in Cloudflare Workers --- .changeset/pretty-canyons-refuse.md | 6 + .changeset/strict-coats-throw.md | 5 + packages/astro-prism/Prism.astro | 2 +- packages/astro-prism/package.json | 6 + packages/astro-prism/src/highlighter.ts | 16 +- .../astro-prism/src/loadLanguages-default.ts | 5 + .../astro-prism/src/loadLanguages-workerd.ts | 76 ++ packages/astro-prism/src/prism/components.ts | 742 ++++++++++++++++++ .../astro-prism/src/prism/dependencies.ts | 460 +++++++++++ packages/astro-prism/tsconfig.json | 3 +- .../test/astro-dev-platform.test.js | 11 + .../fixtures/astro-dev-platform/package.json | 1 + .../src/pages/prism-test.astro | 12 + .../markdoc/src/extensions/prism.ts | 4 +- packages/markdown/remark/src/rehype-prism.ts | 8 +- pnpm-lock.yaml | 3 + 16 files changed, 1343 insertions(+), 17 deletions(-) create mode 100644 .changeset/pretty-canyons-refuse.md create mode 100644 .changeset/strict-coats-throw.md create mode 100644 packages/astro-prism/src/loadLanguages-default.ts create mode 100644 packages/astro-prism/src/loadLanguages-workerd.ts create mode 100644 packages/astro-prism/src/prism/components.ts create mode 100644 packages/astro-prism/src/prism/dependencies.ts create mode 100644 packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro diff --git a/.changeset/pretty-canyons-refuse.md b/.changeset/pretty-canyons-refuse.md new file mode 100644 index 000000000000..28401e9e9e90 --- /dev/null +++ b/.changeset/pretty-canyons-refuse.md @@ -0,0 +1,6 @@ +--- +'@astrojs/markdoc': patch +'@astrojs/markdown-remark': patch +--- + +Updates internal type usage from `@astrojs/prism`. diff --git a/.changeset/strict-coats-throw.md b/.changeset/strict-coats-throw.md new file mode 100644 index 000000000000..699f884eabe0 --- /dev/null +++ b/.changeset/strict-coats-throw.md @@ -0,0 +1,5 @@ +--- +'@astrojs/prism': patch +--- + +Fixes an issue where the `` component failed to work in Cloudflare Workers. diff --git a/packages/astro-prism/Prism.astro b/packages/astro-prism/Prism.astro index 9306024a18a6..ad35461512c0 100644 --- a/packages/astro-prism/Prism.astro +++ b/packages/astro-prism/Prism.astro @@ -8,7 +8,7 @@ interface Props { } const { class: className, lang, code } = Astro.props as Props; -const { classLanguage, html } = runHighlighterWithAstro(lang, code); +const { classLanguage, html } = await runHighlighterWithAstro(lang, code); ---
 {
+	const ensureLoaded = async (language: string) => {
 		if (language && !Prism.languages[language]) {
-			loadLanguages([language]);
+			await loadLanguages([language]);
 		}
 	};
 
 	if (languageMap.has(lang)) {
-		ensureLoaded(languageMap.get(lang)!);
+		await ensureLoaded(languageMap.get(lang)!);
 	} else if (lang === 'astro') {
-		ensureLoaded('typescript');
+		await ensureLoaded('typescript');
 		addAstro(Prism);
 	} else {
-		ensureLoaded('markup-templating'); // Prism expects this to exist for a number of other langs
-		ensureLoaded(lang);
+		await ensureLoaded('markup-templating'); // Prism expects this to exist for a number of other langs
+		await ensureLoaded(lang);
 	}
 
 	if (lang && !Prism.languages[lang]) {
diff --git a/packages/astro-prism/src/loadLanguages-default.ts b/packages/astro-prism/src/loadLanguages-default.ts
new file mode 100644
index 000000000000..bfe3d6469787
--- /dev/null
+++ b/packages/astro-prism/src/loadLanguages-default.ts
@@ -0,0 +1,5 @@
+import prismLoadLanguages from 'prismjs/components/index.js';
+
+export default async function loadLanguages(languages: string | string[]) {
+	return prismLoadLanguages(languages);
+}
diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts
new file mode 100644
index 000000000000..0282fb6b344a
--- /dev/null
+++ b/packages/astro-prism/src/loadLanguages-workerd.ts
@@ -0,0 +1,76 @@
+// This implementation was based from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components/index.js
+import Prism from 'prismjs';
+import { components } from './prism/components.js';
+import { getLoader } from './prism/dependencies.js';
+
+const prismLanguageFiles = import.meta.glob('../node_modules/prismjs/components/prism-*.js');
+
+// Since Prism language files are written assuming the Prism instance is defined
+// as a global variable, we will temporarily set the Prism instance globally.
+function setPrismAsGlobal() {
+	globalThis.Prism = Prism;
+
+	return () => {
+		// @ts-expect-error globalThis type
+		delete globalThis.Prism;
+	};
+}
+
+/**
+ * The set of all languages which have been loaded using the below function.
+ *
+ * @type {Set}
+ */
+const loadedLanguages = new Set();
+
+/**
+ * Loads the given languages and adds them to the current Prism instance.
+ *
+ * If no languages are provided, __all__ Prism languages will be loaded.
+ *
+ * @param {string|string[]} [languages]
+ * @returns {Promise}
+ */
+export default async function loadLanguages(languages: string | string[]) {
+	const cleanUp = setPrismAsGlobal();
+
+	let resolve: VoidFunction;
+	const promise = new Promise((r) => (resolve = r));
+
+	if (languages === undefined) {
+		languages = Object.keys(components.languages).filter((l) => l !== 'meta');
+	} else if (!Array.isArray(languages)) {
+		languages = [languages];
+	}
+
+	// the user might have loaded languages via some other way or used `prism.js` which already includes some
+	// we don't need to validate the ids because `getLoader` will ignore invalid ones
+	const loaded = [...loadedLanguages, ...Object.keys(Prism.languages)];
+
+	// @ts-expect-error `load` arguments type
+	getLoader(components, languages, loaded).load(async (lang: string) => {
+		if (!(lang in components.languages)) {
+			if (!loadLanguages.silent) {
+				console.warn('Language does not exist: ' + lang);
+			}
+			return;
+		}
+
+		const pathToLanguage = `../node_modules/prismjs/components/prism-${lang}.js`;
+
+		// remove from Prism
+		delete Prism.languages[lang];
+
+		await prismLanguageFiles[pathToLanguage]();
+
+		loadedLanguages.add(lang);
+		resolve();
+	});
+
+	return promise.then(cleanUp);
+}
+
+/**
+ * Set this to `true` to prevent all warning messages `loadLanguages` logs.
+ */
+loadLanguages.silent = false;
diff --git a/packages/astro-prism/src/prism/components.ts b/packages/astro-prism/src/prism/components.ts
new file mode 100644
index 000000000000..68aa996eb446
--- /dev/null
+++ b/packages/astro-prism/src/prism/components.ts
@@ -0,0 +1,742 @@
+// This implementation was ported from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components.js
+// biome-ignore-all lint: Ported from the original source as-is
+// eslint-disable-next-line no-var
+export var components = {
+	core: { meta: { path: 'components/prism-core.js', option: 'mandatory' }, core: 'Core' },
+	themes: {
+		meta: { path: 'themes/{id}.css', link: 'index.html?theme={id}', exclusive: true },
+		prism: { title: 'Default', option: 'default' },
+		'prism-dark': 'Dark',
+		'prism-funky': 'Funky',
+		'prism-okaidia': { title: 'Okaidia', owner: 'ocodia' },
+		'prism-twilight': { title: 'Twilight', owner: 'remybach' },
+		'prism-coy': { title: 'Coy', owner: 'tshedor' },
+		'prism-solarizedlight': { title: 'Solarized Light', owner: 'hectormatos2011 ' },
+		'prism-tomorrow': { title: 'Tomorrow Night', owner: 'Rosey' },
+	},
+	languages: {
+		meta: {
+			path: 'components/prism-{id}',
+			noCSS: true,
+			examplesPath: 'examples/prism-{id}',
+			addCheckAll: true,
+		},
+		markup: {
+			title: 'Markup',
+			alias: ['html', 'xml', 'svg', 'mathml', 'ssml', 'atom', 'rss'],
+			aliasTitles: {
+				html: 'HTML',
+				xml: 'XML',
+				svg: 'SVG',
+				mathml: 'MathML',
+				ssml: 'SSML',
+				atom: 'Atom',
+				rss: 'RSS',
+			},
+			option: 'default',
+		},
+		css: { title: 'CSS', option: 'default', modify: 'markup' },
+		clike: { title: 'C-like', option: 'default' },
+		javascript: {
+			title: 'JavaScript',
+			require: 'clike',
+			modify: 'markup',
+			optional: 'regex',
+			alias: 'js',
+			option: 'default',
+		},
+		abap: { title: 'ABAP', owner: 'dellagustin' },
+		abnf: { title: 'ABNF', owner: 'RunDevelopment' },
+		actionscript: {
+			title: 'ActionScript',
+			require: 'javascript',
+			modify: 'markup',
+			owner: 'Golmote',
+		},
+		ada: { title: 'Ada', owner: 'Lucretia' },
+		agda: { title: 'Agda', owner: 'xy-ren' },
+		al: { title: 'AL', owner: 'RunDevelopment' },
+		antlr4: { title: 'ANTLR4', alias: 'g4', owner: 'RunDevelopment' },
+		apacheconf: { title: 'Apache Configuration', owner: 'GuiTeK' },
+		apex: { title: 'Apex', require: ['clike', 'sql'], owner: 'RunDevelopment' },
+		apl: { title: 'APL', owner: 'ngn' },
+		applescript: { title: 'AppleScript', owner: 'Golmote' },
+		aql: { title: 'AQL', owner: 'RunDevelopment' },
+		arduino: { title: 'Arduino', require: 'cpp', alias: 'ino', owner: 'dkern' },
+		arff: { title: 'ARFF', owner: 'Golmote' },
+		armasm: { title: 'ARM Assembly', alias: 'arm-asm', owner: 'RunDevelopment' },
+		arturo: {
+			title: 'Arturo',
+			alias: 'art',
+			optional: ['bash', 'css', 'javascript', 'markup', 'markdown', 'sql'],
+			owner: 'drkameleon',
+		},
+		asciidoc: { alias: 'adoc', title: 'AsciiDoc', owner: 'Golmote' },
+		aspnet: { title: 'ASP.NET (C#)', require: ['markup', 'csharp'], owner: 'nauzilus' },
+		asm6502: { title: '6502 Assembly', owner: 'kzurawel' },
+		asmatmel: { title: 'Atmel AVR Assembly', owner: 'cerkit' },
+		autohotkey: { title: 'AutoHotkey', owner: 'aviaryan' },
+		autoit: { title: 'AutoIt', owner: 'Golmote' },
+		avisynth: { title: 'AviSynth', alias: 'avs', owner: 'Zinfidel' },
+		'avro-idl': { title: 'Avro IDL', alias: 'avdl', owner: 'RunDevelopment' },
+		awk: { title: 'AWK', alias: 'gawk', aliasTitles: { gawk: 'GAWK' }, owner: 'RunDevelopment' },
+		bash: {
+			title: 'Bash',
+			alias: ['sh', 'shell'],
+			aliasTitles: { sh: 'Shell', shell: 'Shell' },
+			owner: 'zeitgeist87',
+		},
+		basic: { title: 'BASIC', owner: 'Golmote' },
+		batch: { title: 'Batch', owner: 'Golmote' },
+		bbcode: {
+			title: 'BBcode',
+			alias: 'shortcode',
+			aliasTitles: { shortcode: 'Shortcode' },
+			owner: 'RunDevelopment',
+		},
+		bbj: { title: 'BBj', owner: 'hyyan' },
+		bicep: { title: 'Bicep', owner: 'johnnyreilly' },
+		birb: { title: 'Birb', require: 'clike', owner: 'Calamity210' },
+		bison: { title: 'Bison', require: 'c', owner: 'Golmote' },
+		bnf: { title: 'BNF', alias: 'rbnf', aliasTitles: { rbnf: 'RBNF' }, owner: 'RunDevelopment' },
+		bqn: { title: 'BQN', owner: 'yewscion' },
+		brainfuck: { title: 'Brainfuck', owner: 'Golmote' },
+		brightscript: { title: 'BrightScript', owner: 'RunDevelopment' },
+		bro: { title: 'Bro', owner: 'wayward710' },
+		bsl: {
+			title: 'BSL (1C:Enterprise)',
+			alias: 'oscript',
+			aliasTitles: { oscript: 'OneScript' },
+			owner: 'Diversus23',
+		},
+		c: { title: 'C', require: 'clike', owner: 'zeitgeist87' },
+		csharp: { title: 'C#', require: 'clike', alias: ['cs', 'dotnet'], owner: 'mvalipour' },
+		cpp: { title: 'C++', require: 'c', owner: 'zeitgeist87' },
+		cfscript: { title: 'CFScript', require: 'clike', alias: 'cfc', owner: 'mjclemente' },
+		chaiscript: { title: 'ChaiScript', require: ['clike', 'cpp'], owner: 'RunDevelopment' },
+		cil: { title: 'CIL', owner: 'sbrl' },
+		cilkc: { title: 'Cilk/C', require: 'c', alias: 'cilk-c', owner: 'OpenCilk' },
+		cilkcpp: { title: 'Cilk/C++', require: 'cpp', alias: ['cilk-cpp', 'cilk'], owner: 'OpenCilk' },
+		clojure: { title: 'Clojure', owner: 'troglotit' },
+		cmake: { title: 'CMake', owner: 'mjrogozinski' },
+		cobol: { title: 'COBOL', owner: 'RunDevelopment' },
+		coffeescript: {
+			title: 'CoffeeScript',
+			require: 'javascript',
+			alias: 'coffee',
+			owner: 'R-osey',
+		},
+		concurnas: { title: 'Concurnas', alias: 'conc', owner: 'jasontatton' },
+		csp: { title: 'Content-Security-Policy', owner: 'ScottHelme' },
+		cooklang: { title: 'Cooklang', owner: 'ahue' },
+		coq: { title: 'Coq', owner: 'RunDevelopment' },
+		crystal: { title: 'Crystal', require: 'ruby', owner: 'MakeNowJust' },
+		'css-extras': { title: 'CSS Extras', require: 'css', modify: 'css', owner: 'milesj' },
+		csv: { title: 'CSV', owner: 'RunDevelopment' },
+		cue: { title: 'CUE', owner: 'RunDevelopment' },
+		cypher: { title: 'Cypher', owner: 'RunDevelopment' },
+		d: { title: 'D', require: 'clike', owner: 'Golmote' },
+		dart: { title: 'Dart', require: 'clike', owner: 'Golmote' },
+		dataweave: { title: 'DataWeave', owner: 'machaval' },
+		dax: { title: 'DAX', owner: 'peterbud' },
+		dhall: { title: 'Dhall', owner: 'RunDevelopment' },
+		diff: { title: 'Diff', owner: 'uranusjr' },
+		django: {
+			title: 'Django/Jinja2',
+			require: 'markup-templating',
+			alias: 'jinja2',
+			owner: 'romanvm',
+		},
+		'dns-zone-file': { title: 'DNS zone file', owner: 'RunDevelopment', alias: 'dns-zone' },
+		docker: { title: 'Docker', alias: 'dockerfile', owner: 'JustinBeckwith' },
+		dot: { title: 'DOT (Graphviz)', alias: 'gv', optional: 'markup', owner: 'RunDevelopment' },
+		ebnf: { title: 'EBNF', owner: 'RunDevelopment' },
+		editorconfig: { title: 'EditorConfig', owner: 'osipxd' },
+		eiffel: { title: 'Eiffel', owner: 'Conaclos' },
+		ejs: {
+			title: 'EJS',
+			require: ['javascript', 'markup-templating'],
+			owner: 'RunDevelopment',
+			alias: 'eta',
+			aliasTitles: { eta: 'Eta' },
+		},
+		elixir: { title: 'Elixir', owner: 'Golmote' },
+		elm: { title: 'Elm', owner: 'zwilias' },
+		etlua: {
+			title: 'Embedded Lua templating',
+			require: ['lua', 'markup-templating'],
+			owner: 'RunDevelopment',
+		},
+		erb: { title: 'ERB', require: ['ruby', 'markup-templating'], owner: 'Golmote' },
+		erlang: { title: 'Erlang', owner: 'Golmote' },
+		'excel-formula': { title: 'Excel Formula', alias: ['xlsx', 'xls'], owner: 'RunDevelopment' },
+		fsharp: { title: 'F#', require: 'clike', owner: 'simonreynolds7' },
+		factor: { title: 'Factor', owner: 'catb0t' },
+		false: { title: 'False', owner: 'edukisto' },
+		'firestore-security-rules': {
+			title: 'Firestore security rules',
+			require: 'clike',
+			owner: 'RunDevelopment',
+		},
+		flow: { title: 'Flow', require: 'javascript', owner: 'Golmote' },
+		fortran: { title: 'Fortran', owner: 'Golmote' },
+		ftl: {
+			title: 'FreeMarker Template Language',
+			require: 'markup-templating',
+			owner: 'RunDevelopment',
+		},
+		gml: {
+			title: 'GameMaker Language',
+			alias: 'gamemakerlanguage',
+			require: 'clike',
+			owner: 'LiarOnce',
+		},
+		gap: { title: 'GAP (CAS)', owner: 'RunDevelopment' },
+		gcode: { title: 'G-code', owner: 'RunDevelopment' },
+		gdscript: { title: 'GDScript', owner: 'RunDevelopment' },
+		gedcom: { title: 'GEDCOM', owner: 'Golmote' },
+		gettext: { title: 'gettext', alias: 'po', owner: 'RunDevelopment' },
+		gherkin: { title: 'Gherkin', owner: 'hason' },
+		git: { title: 'Git', owner: 'lgiraudel' },
+		glsl: { title: 'GLSL', require: 'c', owner: 'Golmote' },
+		gn: { title: 'GN', alias: 'gni', owner: 'RunDevelopment' },
+		'linker-script': { title: 'GNU Linker Script', alias: 'ld', owner: 'RunDevelopment' },
+		go: { title: 'Go', require: 'clike', owner: 'arnehormann' },
+		'go-module': { title: 'Go module', alias: 'go-mod', owner: 'RunDevelopment' },
+		gradle: { title: 'Gradle', require: 'clike', owner: 'zeabdelkhalek-badido18' },
+		graphql: { title: 'GraphQL', optional: 'markdown', owner: 'Golmote' },
+		groovy: { title: 'Groovy', require: 'clike', owner: 'robfletcher' },
+		haml: {
+			title: 'Haml',
+			require: 'ruby',
+			optional: [
+				'css',
+				'css-extras',
+				'coffeescript',
+				'erb',
+				'javascript',
+				'less',
+				'markdown',
+				'scss',
+				'textile',
+			],
+			owner: 'Golmote',
+		},
+		handlebars: {
+			title: 'Handlebars',
+			require: 'markup-templating',
+			alias: ['hbs', 'mustache'],
+			aliasTitles: { mustache: 'Mustache' },
+			owner: 'Golmote',
+		},
+		haskell: { title: 'Haskell', alias: 'hs', owner: 'bholst' },
+		haxe: { title: 'Haxe', require: 'clike', optional: 'regex', owner: 'Golmote' },
+		hcl: { title: 'HCL', owner: 'outsideris' },
+		hlsl: { title: 'HLSL', require: 'c', owner: 'RunDevelopment' },
+		hoon: { title: 'Hoon', owner: 'matildepark' },
+		http: {
+			title: 'HTTP',
+			optional: ['csp', 'css', 'hpkp', 'hsts', 'javascript', 'json', 'markup', 'uri'],
+			owner: 'danielgtaylor',
+		},
+		hpkp: { title: 'HTTP Public-Key-Pins', owner: 'ScottHelme' },
+		hsts: { title: 'HTTP Strict-Transport-Security', owner: 'ScottHelme' },
+		ichigojam: { title: 'IchigoJam', owner: 'BlueCocoa' },
+		icon: { title: 'Icon', owner: 'Golmote' },
+		'icu-message-format': { title: 'ICU Message Format', owner: 'RunDevelopment' },
+		idris: { title: 'Idris', alias: 'idr', owner: 'KeenS', require: 'haskell' },
+		ignore: {
+			title: '.ignore',
+			owner: 'osipxd',
+			alias: ['gitignore', 'hgignore', 'npmignore'],
+			aliasTitles: { gitignore: '.gitignore', hgignore: '.hgignore', npmignore: '.npmignore' },
+		},
+		inform7: { title: 'Inform 7', owner: 'Golmote' },
+		ini: { title: 'Ini', owner: 'aviaryan' },
+		io: { title: 'Io', owner: 'AlesTsurko' },
+		j: { title: 'J', owner: 'Golmote' },
+		java: { title: 'Java', require: 'clike', owner: 'sherblot' },
+		javadoc: {
+			title: 'JavaDoc',
+			require: ['markup', 'java', 'javadoclike'],
+			modify: 'java',
+			optional: 'scala',
+			owner: 'RunDevelopment',
+		},
+		javadoclike: {
+			title: 'JavaDoc-like',
+			modify: ['java', 'javascript', 'php'],
+			owner: 'RunDevelopment',
+		},
+		javastacktrace: { title: 'Java stack trace', owner: 'RunDevelopment' },
+		jexl: { title: 'Jexl', owner: 'czosel' },
+		jolie: { title: 'Jolie', require: 'clike', owner: 'thesave' },
+		jq: { title: 'JQ', owner: 'RunDevelopment' },
+		jsdoc: {
+			title: 'JSDoc',
+			require: ['javascript', 'javadoclike', 'typescript'],
+			modify: 'javascript',
+			optional: ['actionscript', 'coffeescript'],
+			owner: 'RunDevelopment',
+		},
+		'js-extras': {
+			title: 'JS Extras',
+			require: 'javascript',
+			modify: 'javascript',
+			optional: ['actionscript', 'coffeescript', 'flow', 'n4js', 'typescript'],
+			owner: 'RunDevelopment',
+		},
+		json: {
+			title: 'JSON',
+			alias: 'webmanifest',
+			aliasTitles: { webmanifest: 'Web App Manifest' },
+			owner: 'CupOfTea696',
+		},
+		json5: { title: 'JSON5', require: 'json', owner: 'RunDevelopment' },
+		jsonp: { title: 'JSONP', require: 'json', owner: 'RunDevelopment' },
+		jsstacktrace: { title: 'JS stack trace', owner: 'sbrl' },
+		'js-templates': {
+			title: 'JS Templates',
+			require: 'javascript',
+			modify: 'javascript',
+			optional: ['css', 'css-extras', 'graphql', 'markdown', 'markup', 'sql'],
+			owner: 'RunDevelopment',
+		},
+		julia: { title: 'Julia', owner: 'cdagnino' },
+		keepalived: { title: 'Keepalived Configure', owner: 'dev-itsheng' },
+		keyman: { title: 'Keyman', owner: 'mcdurdin' },
+		kotlin: {
+			title: 'Kotlin',
+			alias: ['kt', 'kts'],
+			aliasTitles: { kts: 'Kotlin Script' },
+			require: 'clike',
+			owner: 'Golmote',
+		},
+		kumir: { title: 'KuMir (КуМир)', alias: 'kum', owner: 'edukisto' },
+		kusto: { title: 'Kusto', owner: 'RunDevelopment' },
+		latex: {
+			title: 'LaTeX',
+			alias: ['tex', 'context'],
+			aliasTitles: { tex: 'TeX', context: 'ConTeXt' },
+			owner: 'japborst',
+		},
+		latte: { title: 'Latte', require: ['clike', 'markup-templating', 'php'], owner: 'nette' },
+		less: { title: 'Less', require: 'css', optional: 'css-extras', owner: 'Golmote' },
+		lilypond: { title: 'LilyPond', require: 'scheme', alias: 'ly', owner: 'RunDevelopment' },
+		liquid: { title: 'Liquid', require: 'markup-templating', owner: 'cinhtau' },
+		lisp: { title: 'Lisp', alias: ['emacs', 'elisp', 'emacs-lisp'], owner: 'JuanCaicedo' },
+		livescript: { title: 'LiveScript', owner: 'Golmote' },
+		llvm: { title: 'LLVM IR', owner: 'porglezomp' },
+		log: { title: 'Log file', optional: 'javastacktrace', owner: 'RunDevelopment' },
+		lolcode: { title: 'LOLCODE', owner: 'Golmote' },
+		lua: { title: 'Lua', owner: 'Golmote' },
+		magma: { title: 'Magma (CAS)', owner: 'RunDevelopment' },
+		makefile: { title: 'Makefile', owner: 'Golmote' },
+		markdown: {
+			title: 'Markdown',
+			require: 'markup',
+			optional: 'yaml',
+			alias: 'md',
+			owner: 'Golmote',
+		},
+		'markup-templating': { title: 'Markup templating', require: 'markup', owner: 'Golmote' },
+		mata: { title: 'Mata', owner: 'RunDevelopment' },
+		matlab: { title: 'MATLAB', owner: 'Golmote' },
+		maxscript: { title: 'MAXScript', owner: 'RunDevelopment' },
+		mel: { title: 'MEL', owner: 'Golmote' },
+		mermaid: { title: 'Mermaid', owner: 'RunDevelopment' },
+		metafont: { title: 'METAFONT', owner: 'LaeriExNihilo' },
+		mizar: { title: 'Mizar', owner: 'Golmote' },
+		mongodb: { title: 'MongoDB', owner: 'airs0urce', require: 'javascript' },
+		monkey: { title: 'Monkey', owner: 'Golmote' },
+		moonscript: { title: 'MoonScript', alias: 'moon', owner: 'RunDevelopment' },
+		n1ql: { title: 'N1QL', owner: 'TMWilds' },
+		n4js: {
+			title: 'N4JS',
+			require: 'javascript',
+			optional: 'jsdoc',
+			alias: 'n4jsd',
+			owner: 'bsmith-n4',
+		},
+		'nand2tetris-hdl': { title: 'Nand To Tetris HDL', owner: 'stephanmax' },
+		naniscript: { title: 'Naninovel Script', owner: 'Elringus', alias: 'nani' },
+		nasm: { title: 'NASM', owner: 'rbmj' },
+		neon: { title: 'NEON', owner: 'nette' },
+		nevod: { title: 'Nevod', owner: 'nezaboodka' },
+		nginx: { title: 'nginx', owner: 'volado' },
+		nim: { title: 'Nim', owner: 'Golmote' },
+		nix: { title: 'Nix', owner: 'Golmote' },
+		nsis: { title: 'NSIS', owner: 'idleberg' },
+		objectivec: { title: 'Objective-C', require: 'c', alias: 'objc', owner: 'uranusjr' },
+		ocaml: { title: 'OCaml', owner: 'Golmote' },
+		odin: { title: 'Odin', owner: 'edukisto' },
+		opencl: { title: 'OpenCL', require: 'c', modify: ['c', 'cpp'], owner: 'Milania1' },
+		openqasm: { title: 'OpenQasm', alias: 'qasm', owner: 'RunDevelopment' },
+		oz: { title: 'Oz', owner: 'Golmote' },
+		parigp: { title: 'PARI/GP', owner: 'Golmote' },
+		parser: { title: 'Parser', require: 'markup', owner: 'Golmote' },
+		pascal: {
+			title: 'Pascal',
+			alias: 'objectpascal',
+			aliasTitles: { objectpascal: 'Object Pascal' },
+			owner: 'Golmote',
+		},
+		pascaligo: { title: 'Pascaligo', owner: 'DefinitelyNotAGoat' },
+		psl: { title: 'PATROL Scripting Language', owner: 'bertysentry' },
+		pcaxis: { title: 'PC-Axis', alias: 'px', owner: 'RunDevelopment' },
+		peoplecode: { title: 'PeopleCode', alias: 'pcode', owner: 'RunDevelopment' },
+		perl: { title: 'Perl', owner: 'Golmote' },
+		php: { title: 'PHP', require: 'markup-templating', owner: 'milesj' },
+		phpdoc: {
+			title: 'PHPDoc',
+			require: ['php', 'javadoclike'],
+			modify: 'php',
+			owner: 'RunDevelopment',
+		},
+		'php-extras': { title: 'PHP Extras', require: 'php', modify: 'php', owner: 'milesj' },
+		'plant-uml': { title: 'PlantUML', alias: 'plantuml', owner: 'RunDevelopment' },
+		plsql: { title: 'PL/SQL', require: 'sql', owner: 'Golmote' },
+		powerquery: { title: 'PowerQuery', alias: ['pq', 'mscript'], owner: 'peterbud' },
+		powershell: { title: 'PowerShell', owner: 'nauzilus' },
+		processing: { title: 'Processing', require: 'clike', owner: 'Golmote' },
+		prolog: { title: 'Prolog', owner: 'Golmote' },
+		promql: { title: 'PromQL', owner: 'arendjr' },
+		properties: { title: '.properties', owner: 'Golmote' },
+		protobuf: { title: 'Protocol Buffers', require: 'clike', owner: 'just-boris' },
+		pug: {
+			title: 'Pug',
+			require: ['markup', 'javascript'],
+			optional: [
+				'coffeescript',
+				'ejs',
+				'handlebars',
+				'less',
+				'livescript',
+				'markdown',
+				'scss',
+				'stylus',
+				'twig',
+			],
+			owner: 'Golmote',
+		},
+		puppet: { title: 'Puppet', owner: 'Golmote' },
+		pure: { title: 'Pure', optional: ['c', 'cpp', 'fortran'], owner: 'Golmote' },
+		purebasic: { title: 'PureBasic', require: 'clike', alias: 'pbfasm', owner: 'HeX0R101' },
+		purescript: {
+			title: 'PureScript',
+			require: 'haskell',
+			alias: 'purs',
+			owner: 'sriharshachilakapati',
+		},
+		python: { title: 'Python', alias: 'py', owner: 'multipetros' },
+		qsharp: { title: 'Q#', require: 'clike', alias: 'qs', owner: 'fedonman' },
+		q: { title: 'Q (kdb+ database)', owner: 'Golmote' },
+		qml: { title: 'QML', require: 'javascript', owner: 'RunDevelopment' },
+		qore: { title: 'Qore', require: 'clike', owner: 'temnroegg' },
+		r: { title: 'R', owner: 'Golmote' },
+		racket: { title: 'Racket', require: 'scheme', alias: 'rkt', owner: 'RunDevelopment' },
+		cshtml: {
+			title: 'Razor C#',
+			alias: 'razor',
+			require: ['markup', 'csharp'],
+			optional: ['css', 'css-extras', 'javascript', 'js-extras'],
+			owner: 'RunDevelopment',
+		},
+		jsx: {
+			title: 'React JSX',
+			require: ['markup', 'javascript'],
+			optional: ['jsdoc', 'js-extras', 'js-templates'],
+			owner: 'vkbansal',
+		},
+		tsx: { title: 'React TSX', require: ['jsx', 'typescript'] },
+		reason: { title: 'Reason', require: 'clike', owner: 'Golmote' },
+		regex: { title: 'Regex', owner: 'RunDevelopment' },
+		rego: { title: 'Rego', owner: 'JordanSh' },
+		renpy: { title: "Ren'py", alias: 'rpy', owner: 'HyuchiaDiego' },
+		rescript: { title: 'ReScript', alias: 'res', owner: 'vmarcosp' },
+		rest: { title: 'reST (reStructuredText)', owner: 'Golmote' },
+		rip: { title: 'Rip', owner: 'ravinggenius' },
+		roboconf: { title: 'Roboconf', owner: 'Golmote' },
+		robotframework: { title: 'Robot Framework', alias: 'robot', owner: 'RunDevelopment' },
+		ruby: { title: 'Ruby', require: 'clike', alias: 'rb', owner: 'samflores' },
+		rust: { title: 'Rust', owner: 'Golmote' },
+		sas: { title: 'SAS', optional: ['groovy', 'lua', 'sql'], owner: 'Golmote' },
+		sass: { title: 'Sass (Sass)', require: 'css', optional: 'css-extras', owner: 'Golmote' },
+		scss: { title: 'Sass (SCSS)', require: 'css', optional: 'css-extras', owner: 'MoOx' },
+		scala: { title: 'Scala', require: 'java', owner: 'jozic' },
+		scheme: { title: 'Scheme', owner: 'bacchus123' },
+		'shell-session': {
+			title: 'Shell session',
+			require: 'bash',
+			alias: ['sh-session', 'shellsession'],
+			owner: 'RunDevelopment',
+		},
+		smali: { title: 'Smali', owner: 'RunDevelopment' },
+		smalltalk: { title: 'Smalltalk', owner: 'Golmote' },
+		smarty: { title: 'Smarty', require: 'markup-templating', optional: 'php', owner: 'Golmote' },
+		sml: {
+			title: 'SML',
+			alias: 'smlnj',
+			aliasTitles: { smlnj: 'SML/NJ' },
+			owner: 'RunDevelopment',
+		},
+		solidity: { title: 'Solidity (Ethereum)', alias: 'sol', require: 'clike', owner: 'glachaud' },
+		'solution-file': { title: 'Solution file', alias: 'sln', owner: 'RunDevelopment' },
+		soy: { title: 'Soy (Closure Template)', require: 'markup-templating', owner: 'Golmote' },
+		sparql: { title: 'SPARQL', require: 'turtle', owner: 'Triply-Dev', alias: 'rq' },
+		'splunk-spl': { title: 'Splunk SPL', owner: 'RunDevelopment' },
+		sqf: { title: 'SQF: Status Quo Function (Arma 3)', require: 'clike', owner: 'RunDevelopment' },
+		sql: { title: 'SQL', owner: 'multipetros' },
+		squirrel: { title: 'Squirrel', require: 'clike', owner: 'RunDevelopment' },
+		stan: { title: 'Stan', owner: 'RunDevelopment' },
+		stata: { title: 'Stata Ado', require: ['mata', 'java', 'python'], owner: 'RunDevelopment' },
+		iecst: { title: 'Structured Text (IEC 61131-3)', owner: 'serhioromano' },
+		stylus: { title: 'Stylus', owner: 'vkbansal' },
+		supercollider: { title: 'SuperCollider', alias: 'sclang', owner: 'RunDevelopment' },
+		swift: { title: 'Swift', owner: 'chrischares' },
+		systemd: { title: 'Systemd configuration file', owner: 'RunDevelopment' },
+		't4-templating': { title: 'T4 templating', owner: 'RunDevelopment' },
+		't4-cs': {
+			title: 'T4 Text Templates (C#)',
+			require: ['t4-templating', 'csharp'],
+			alias: 't4',
+			owner: 'RunDevelopment',
+		},
+		't4-vb': {
+			title: 'T4 Text Templates (VB)',
+			require: ['t4-templating', 'vbnet'],
+			owner: 'RunDevelopment',
+		},
+		tap: { title: 'TAP', owner: 'isaacs', require: 'yaml' },
+		tcl: { title: 'Tcl', owner: 'PeterChaplin' },
+		tt2: { title: 'Template Toolkit 2', require: ['clike', 'markup-templating'], owner: 'gflohr' },
+		textile: { title: 'Textile', require: 'markup', optional: 'css', owner: 'Golmote' },
+		toml: { title: 'TOML', owner: 'RunDevelopment' },
+		tremor: {
+			title: 'Tremor',
+			alias: ['trickle', 'troy'],
+			owner: 'darach',
+			aliasTitles: { trickle: 'trickle', troy: 'troy' },
+		},
+		turtle: { title: 'Turtle', alias: 'trig', aliasTitles: { trig: 'TriG' }, owner: 'jakubklimek' },
+		twig: { title: 'Twig', require: 'markup-templating', owner: 'brandonkelly' },
+		typescript: {
+			title: 'TypeScript',
+			require: 'javascript',
+			optional: 'js-templates',
+			alias: 'ts',
+			owner: 'vkbansal',
+		},
+		typoscript: {
+			title: 'TypoScript',
+			alias: 'tsconfig',
+			aliasTitles: { tsconfig: 'TSConfig' },
+			owner: 'dkern',
+		},
+		unrealscript: { title: 'UnrealScript', alias: ['uscript', 'uc'], owner: 'RunDevelopment' },
+		uorazor: { title: 'UO Razor Script', owner: 'jaseowns' },
+		uri: { title: 'URI', alias: 'url', aliasTitles: { url: 'URL' }, owner: 'RunDevelopment' },
+		v: { title: 'V', require: 'clike', owner: 'taggon' },
+		vala: { title: 'Vala', require: 'clike', optional: 'regex', owner: 'TemplarVolk' },
+		vbnet: { title: 'VB.Net', require: 'basic', owner: 'Bigsby' },
+		velocity: { title: 'Velocity', require: 'markup', owner: 'Golmote' },
+		verilog: { title: 'Verilog', owner: 'a-rey' },
+		vhdl: { title: 'VHDL', owner: 'a-rey' },
+		vim: { title: 'vim', owner: 'westonganger' },
+		'visual-basic': {
+			title: 'Visual Basic',
+			alias: ['vb', 'vba'],
+			aliasTitles: { vba: 'VBA' },
+			owner: 'Golmote',
+		},
+		warpscript: { title: 'WarpScript', owner: 'RunDevelopment' },
+		wasm: { title: 'WebAssembly', owner: 'Golmote' },
+		'web-idl': { title: 'Web IDL', alias: 'webidl', owner: 'RunDevelopment' },
+		wgsl: { title: 'WGSL', owner: 'Dr4gonthree' },
+		wiki: { title: 'Wiki markup', require: 'markup', owner: 'Golmote' },
+		wolfram: {
+			title: 'Wolfram language',
+			alias: ['mathematica', 'nb', 'wl'],
+			aliasTitles: { mathematica: 'Mathematica', nb: 'Mathematica Notebook' },
+			owner: 'msollami',
+		},
+		wren: { title: 'Wren', owner: 'clsource' },
+		xeora: {
+			title: 'Xeora',
+			require: 'markup',
+			alias: 'xeoracube',
+			aliasTitles: { xeoracube: 'XeoraCube' },
+			owner: 'freakmaxi',
+		},
+		'xml-doc': {
+			title: 'XML doc (.net)',
+			require: 'markup',
+			modify: ['csharp', 'fsharp', 'vbnet'],
+			owner: 'RunDevelopment',
+		},
+		xojo: { title: 'Xojo (REALbasic)', owner: 'Golmote' },
+		xquery: { title: 'XQuery', require: 'markup', owner: 'Golmote' },
+		yaml: { title: 'YAML', alias: 'yml', owner: 'hason' },
+		yang: { title: 'YANG', owner: 'RunDevelopment' },
+		zig: { title: 'Zig', owner: 'RunDevelopment' },
+	},
+	plugins: {
+		meta: { path: 'plugins/{id}/prism-{id}', link: 'plugins/{id}/' },
+		'line-highlight': {
+			title: 'Line Highlight',
+			description: 'Highlights specific lines and/or line ranges.',
+		},
+		'line-numbers': {
+			title: 'Line Numbers',
+			description: 'Line number at the beginning of code lines.',
+			owner: 'kuba-kubula',
+		},
+		'show-invisibles': {
+			title: 'Show Invisibles',
+			description: 'Show hidden characters such as tabs and line breaks.',
+			optional: ['autolinker', 'data-uri-highlight'],
+		},
+		autolinker: {
+			title: 'Autolinker',
+			description:
+				'Converts URLs and emails in code to clickable links. Parses Markdown links in comments.',
+		},
+		wpd: {
+			title: 'WebPlatform Docs',
+			description:
+				'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.',
+		},
+		'custom-class': {
+			title: 'Custom Class',
+			description:
+				"This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.",
+			owner: 'dvkndn',
+			noCSS: true,
+		},
+		'file-highlight': {
+			title: 'File Highlight',
+			description:
+				'Fetch external files and highlight them with Prism. Used on the Prism website itself.',
+			noCSS: true,
+		},
+		'show-language': {
+			title: 'Show Language',
+			description:
+				'Display the highlighted language in code blocks (inline code does not show the label).',
+			owner: 'nauzilus',
+			noCSS: true,
+			require: 'toolbar',
+		},
+		'jsonp-highlight': {
+			title: 'JSONP Highlight',
+			description:
+				'Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).',
+			noCSS: true,
+			owner: 'nauzilus',
+		},
+		'highlight-keywords': {
+			title: 'Highlight Keywords',
+			description: 'Adds special CSS classes for each keyword for fine-grained highlighting.',
+			owner: 'vkbansal',
+			noCSS: true,
+		},
+		'remove-initial-line-feed': {
+			title: 'Remove initial line feed',
+			description: 'Removes the initial line feed in code blocks.',
+			owner: 'Golmote',
+			noCSS: true,
+		},
+		'inline-color': {
+			title: 'Inline color',
+			description: 'Adds a small inline preview for colors in style sheets.',
+			require: 'css-extras',
+			owner: 'RunDevelopment',
+		},
+		previewers: {
+			title: 'Previewers',
+			description: 'Previewers for angles, colors, gradients, easing and time.',
+			require: 'css-extras',
+			owner: 'Golmote',
+		},
+		autoloader: {
+			title: 'Autoloader',
+			description: 'Automatically loads the needed languages to highlight the code blocks.',
+			owner: 'Golmote',
+			noCSS: true,
+		},
+		'keep-markup': {
+			title: 'Keep Markup',
+			description: 'Prevents custom markup from being dropped out during highlighting.',
+			owner: 'Golmote',
+			optional: 'normalize-whitespace',
+			noCSS: true,
+		},
+		'command-line': {
+			title: 'Command Line',
+			description:
+				'Display a command line with a prompt and, optionally, the output/response from the commands.',
+			owner: 'chriswells0',
+		},
+		'unescaped-markup': {
+			title: 'Unescaped Markup',
+			description: 'Write markup without having to escape anything.',
+		},
+		'normalize-whitespace': {
+			title: 'Normalize Whitespace',
+			description: 'Supports multiple operations to normalize whitespace in code blocks.',
+			owner: 'zeitgeist87',
+			optional: 'unescaped-markup',
+			noCSS: true,
+		},
+		'data-uri-highlight': {
+			title: 'Data-URI Highlight',
+			description: 'Highlights data-URI contents.',
+			owner: 'Golmote',
+			noCSS: true,
+		},
+		toolbar: {
+			title: 'Toolbar',
+			description:
+				'Attach a toolbar for plugins to easily register buttons on the top of a code block.',
+			owner: 'mAAdhaTTah',
+		},
+		'copy-to-clipboard': {
+			title: 'Copy to Clipboard Button',
+			description: 'Add a button that copies the code block to the clipboard when clicked.',
+			owner: 'mAAdhaTTah',
+			require: 'toolbar',
+			noCSS: true,
+		},
+		'download-button': {
+			title: 'Download Button',
+			description:
+				'A button in the toolbar of a code block adding a convenient way to download a code file.',
+			owner: 'Golmote',
+			require: 'toolbar',
+			noCSS: true,
+		},
+		'match-braces': {
+			title: 'Match braces',
+			description: 'Highlights matching braces.',
+			owner: 'RunDevelopment',
+		},
+		'diff-highlight': {
+			title: 'Diff Highlight',
+			description: 'Highlights the code inside diff blocks.',
+			owner: 'RunDevelopment',
+			require: 'diff',
+		},
+		'filter-highlight-all': {
+			title: 'Filter highlightAll',
+			description:
+				'Filters the elements the highlightAll and highlightAllUnder methods actually highlight.',
+			owner: 'RunDevelopment',
+			noCSS: true,
+		},
+		treeview: {
+			title: 'Treeview',
+			description: 'A language with special styles to highlight file system tree structures.',
+			owner: 'Golmote',
+		},
+	},
+};
diff --git a/packages/astro-prism/src/prism/dependencies.ts b/packages/astro-prism/src/prism/dependencies.ts
new file mode 100644
index 000000000000..4cc59d255541
--- /dev/null
+++ b/packages/astro-prism/src/prism/dependencies.ts
@@ -0,0 +1,460 @@
+// This implementation was ported from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/dependencies.js
+// biome-ignore-all lint: Ported from the original source as-is
+// @ts-nocheck
+/* eslint-disable */
+
+'use strict';
+
+/**
+ * @typedef {Object} Components
+ * @typedef {Object} ComponentCategory
+ *
+ * @typedef ComponentEntry
+ * @property {string} [title] The title of the component.
+ * @property {string} [owner] The GitHub user name of the owner.
+ * @property {boolean} [noCSS=false] Whether the component doesn't have style sheets which should also be loaded.
+ * @property {string | string[]} [alias] An optional list of aliases for the id of the component.
+ * @property {Object} [aliasTitles] An optional map from an alias to its title.
+ *
+ * Aliases which are not in this map will the get title of the component.
+ * @property {string | string[]} [optional]
+ * @property {string | string[]} [require]
+ * @property {string | string[]} [modify]
+ */
+
+export var getLoader = (function () {
+	/**
+	 * A function which does absolutely nothing.
+	 *
+	 * @type {any}
+	 */
+	var noop = function () {};
+
+	/**
+	 * Invokes the given callback for all elements of the given value.
+	 *
+	 * If the given value is an array, the callback will be invokes for all elements. If the given value is `null` or
+	 * `undefined`, the callback will not be invoked. In all other cases, the callback will be invoked with the given
+	 * value as parameter.
+	 *
+	 * @param {null | undefined | T | T[]} value
+	 * @param {(value: T, index: number) => void} callbackFn
+	 * @returns {void}
+	 * @template T
+	 */
+	function forEach(value, callbackFn) {
+		if (Array.isArray(value)) {
+			value.forEach(callbackFn);
+		} else if (value != null) {
+			callbackFn(value, 0);
+		}
+	}
+
+	/**
+	 * Returns a new set for the given string array.
+	 *
+	 * @param {string[]} array
+	 * @returns {StringSet}
+	 *
+	 * @typedef {Object} StringSet
+	 */
+	function toSet(array) {
+		/** @type {StringSet} */
+		var set = {};
+		for (var i = 0, l = array.length; i < l; i++) {
+			set[array[i]] = true;
+		}
+		return set;
+	}
+
+	/**
+	 * Creates a map of every components id to its entry.
+	 *
+	 * @param {Components} components
+	 * @returns {EntryMap}
+	 *
+	 * @typedef {{ readonly [id: string]: Readonly | undefined }} EntryMap
+	 */
+	function createEntryMap(components) {
+		/** @type {Object>} */
+		var map = {};
+
+		for (var categoryName in components) {
+			var category = components[categoryName];
+			for (var id in category) {
+				if (id != 'meta') {
+					/** @type {ComponentEntry | string} */
+					var entry = category[id];
+					map[id] = typeof entry == 'string' ? { title: entry } : entry;
+				}
+			}
+		}
+
+		return map;
+	}
+
+	/**
+	 * Creates a full dependencies map which includes all types of dependencies and their transitive dependencies.
+	 *
+	 * @param {EntryMap} entryMap
+	 * @returns {DependencyResolver}
+	 *
+	 * @typedef {(id: string) => StringSet} DependencyResolver
+	 */
+	function createDependencyResolver(entryMap) {
+		/** @type {Object} */
+		var map = {};
+		var _stackArray = [];
+
+		/**
+		 * Adds the dependencies of the given component to the dependency map.
+		 *
+		 * @param {string} id
+		 * @param {string[]} stack
+		 */
+		function addToMap(id, stack) {
+			if (id in map) {
+				return;
+			}
+
+			stack.push(id);
+
+			// check for circular dependencies
+			var firstIndex = stack.indexOf(id);
+			if (firstIndex < stack.length - 1) {
+				throw new Error('Circular dependency: ' + stack.slice(firstIndex).join(' -> '));
+			}
+
+			/** @type {StringSet} */
+			var dependencies = {};
+
+			var entry = entryMap[id];
+			if (entry) {
+				/**
+				 * This will add the direct dependency and all of its transitive dependencies to the set of
+				 * dependencies of `entry`.
+				 *
+				 * @param {string} depId
+				 * @returns {void}
+				 */
+				function handleDirectDependency(depId) {
+					if (!(depId in entryMap)) {
+						throw new Error(id + ' depends on an unknown component ' + depId);
+					}
+					if (depId in dependencies) {
+						// if the given dependency is already in the set of deps, then so are its transitive deps
+						return;
+					}
+
+					addToMap(depId, stack);
+					dependencies[depId] = true;
+					for (var transitiveDepId in map[depId]) {
+						dependencies[transitiveDepId] = true;
+					}
+				}
+
+				forEach(entry.require, handleDirectDependency);
+				forEach(entry.optional, handleDirectDependency);
+				forEach(entry.modify, handleDirectDependency);
+			}
+
+			map[id] = dependencies;
+
+			stack.pop();
+		}
+
+		return function (id) {
+			var deps = map[id];
+			if (!deps) {
+				addToMap(id, _stackArray);
+				deps = map[id];
+			}
+			return deps;
+		};
+	}
+
+	/**
+	 * Returns a function which resolves the aliases of its given id of alias.
+	 *
+	 * @param {EntryMap} entryMap
+	 * @returns {(idOrAlias: string) => string}
+	 */
+	function createAliasResolver(entryMap) {
+		/** @type {Object | undefined} */
+		var map;
+
+		return function (idOrAlias) {
+			if (idOrAlias in entryMap) {
+				return idOrAlias;
+			} else {
+				// only create the alias map if necessary
+				if (!map) {
+					map = {};
+
+					for (var id in entryMap) {
+						var entry = entryMap[id];
+						forEach(entry && entry.alias, function (alias) {
+							if (alias in map) {
+								throw new Error(alias + ' cannot be alias for both ' + id + ' and ' + map[alias]);
+							}
+							if (alias in entryMap) {
+								throw new Error(
+									alias + ' cannot be alias of ' + id + ' because it is a component.',
+								);
+							}
+							map[alias] = id;
+						});
+					}
+				}
+				return map[idOrAlias] || idOrAlias;
+			}
+		};
+	}
+
+	/**
+	 * @typedef LoadChainer
+	 * @property {(before: T, after: () => T) => T} series
+	 * @property {(values: T[]) => T} parallel
+	 * @template T
+	 */
+
+	/**
+	 * Creates an implicit DAG from the given components and dependencies and call the given `loadComponent` for each
+	 * component in topological order.
+	 *
+	 * @param {DependencyResolver} dependencyResolver
+	 * @param {StringSet} ids
+	 * @param {(id: string) => T} loadComponent
+	 * @param {LoadChainer} [chainer]
+	 * @returns {T}
+	 * @template T
+	 */
+	function loadComponentsInOrder(dependencyResolver, ids, loadComponent, chainer) {
+		var series = chainer ? chainer.series : undefined;
+		var parallel = chainer ? chainer.parallel : noop;
+
+		/** @type {Object} */
+		var cache = {};
+
+		/**
+		 * A set of ids of nodes which are not depended upon by any other node in the graph.
+		 *
+		 * @type {StringSet}
+		 */
+		var ends = {};
+
+		/**
+		 * Loads the given component and its dependencies or returns the cached value.
+		 *
+		 * @param {string} id
+		 * @returns {T}
+		 */
+		function handleId(id) {
+			if (id in cache) {
+				return cache[id];
+			}
+
+			// assume that it's an end
+			// if it isn't, it will be removed later
+			ends[id] = true;
+
+			// all dependencies of the component in the given ids
+			var dependsOn = [];
+			for (var depId in dependencyResolver(id)) {
+				if (depId in ids) {
+					dependsOn.push(depId);
+				}
+			}
+
+			/**
+			 * The value to be returned.
+			 *
+			 * @type {T}
+			 */
+			var value;
+
+			if (dependsOn.length === 0) {
+				value = loadComponent(id);
+			} else {
+				// eslint-disable-next-line @typescript-eslint/no-shadow
+				var depsValue = parallel(
+					dependsOn.map(function (depId) {
+						// eslint-disable-next-line @typescript-eslint/no-shadow
+						var value = handleId(depId);
+						// none of the dependencies can be ends
+						delete ends[depId];
+						return value;
+					}),
+				);
+				if (series) {
+					// the chainer will be responsibly for calling the function calling loadComponent
+					value = series(depsValue, function () {
+						return loadComponent(id);
+					});
+				} else {
+					// we don't have a chainer, so we call loadComponent ourselves
+					loadComponent(id);
+				}
+			}
+
+			// cache and return
+			return (cache[id] = value);
+		}
+
+		for (var id in ids) {
+			handleId(id);
+		}
+
+		/** @type {T[]} */
+		var endValues = [];
+		for (var endId in ends) {
+			endValues.push(cache[endId]);
+		}
+		return parallel(endValues);
+	}
+
+	/**
+	 * Returns whether the given object has any keys.
+	 *
+	 * @param {object} obj
+	 */
+	function hasKeys(obj) {
+		for (var key in obj) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Returns an object which provides methods to get the ids of the components which have to be loaded (`getIds`) and
+	 * a way to efficiently load them in synchronously and asynchronous contexts (`load`).
+	 *
+	 * The set of ids to be loaded is a superset of `load`. If some of these ids are in `loaded`, the corresponding
+	 * components will have to reloaded.
+	 *
+	 * The ids in `load` and `loaded` may be in any order and can contain duplicates.
+	 *
+	 * @param {Components} components
+	 * @param {string[]} load
+	 * @param {string[]} [loaded=[]] A list of already loaded components.
+	 *
+	 * If a component is in this list, then all of its requirements will also be assumed to be in the list.
+	 * @returns {Loader}
+	 *
+	 * @typedef Loader
+	 * @property {() => string[]} getIds A function to get all ids of the components to load.
+	 *
+	 * The returned ids will be duplicate-free, alias-free and in load order.
+	 * @property {LoadFunction} load A functional interface to load components.
+	 *
+	 * @typedef { (loadComponent: (id: string) => T, chainer?: LoadChainer) => T} LoadFunction
+	 * A functional interface to load components.
+	 *
+	 * The `loadComponent` function will be called for every component in the order in which they have to be loaded.
+	 *
+	 * The `chainer` is useful for asynchronous loading and its `series` and `parallel` functions can be thought of as
+	 * `Promise#then` and `Promise.all`.
+	 *
+	 * @example
+	 * load(id => { loadComponent(id); }); // returns undefined
+	 *
+	 * await load(
+	 *     id => loadComponentAsync(id), // returns a Promise for each id
+	 *     {
+	 *         series: async (before, after) => {
+	 *             await before;
+	 *             await after();
+	 *         },
+	 *         parallel: async (values) => {
+	 *             await Promise.all(values);
+	 *         }
+	 *     }
+	 * );
+	 */
+	// eslint-disable-next-line @typescript-eslint/no-shadow
+	function getLoader(components, load, loaded) {
+		var entryMap = createEntryMap(components);
+		var resolveAlias = createAliasResolver(entryMap);
+
+		load = load.map(resolveAlias);
+		loaded = (loaded || []).map(resolveAlias);
+
+		var loadSet = toSet(load);
+		var loadedSet = toSet(loaded);
+
+		// add requirements
+
+		load.forEach(addRequirements);
+		function addRequirements(id) {
+			var entry = entryMap[id];
+			forEach(entry && entry.require, function (reqId) {
+				if (!(reqId in loadedSet)) {
+					loadSet[reqId] = true;
+					addRequirements(reqId);
+				}
+			});
+		}
+
+		// add components to reload
+
+		// A component x in `loaded` has to be reloaded if
+		//  1) a component in `load` modifies x.
+		//  2) x depends on a component in `load`.
+		// The above two condition have to be applied until nothing changes anymore.
+
+		var dependencyResolver = createDependencyResolver(entryMap);
+
+		/** @type {StringSet} */
+		var loadAdditions = loadSet;
+		/** @type {StringSet} */
+		var newIds;
+		while (hasKeys(loadAdditions)) {
+			newIds = {};
+
+			// condition 1)
+			for (var loadId in loadAdditions) {
+				var entry = entryMap[loadId];
+				forEach(entry && entry.modify, function (modId) {
+					if (modId in loadedSet) {
+						newIds[modId] = true;
+					}
+				});
+			}
+
+			// condition 2)
+			for (var loadedId in loadedSet) {
+				if (!(loadedId in loadSet)) {
+					for (var depId in dependencyResolver(loadedId)) {
+						if (depId in loadSet) {
+							newIds[loadedId] = true;
+							break;
+						}
+					}
+				}
+			}
+
+			loadAdditions = newIds;
+			for (var newId in loadAdditions) {
+				loadSet[newId] = true;
+			}
+		}
+
+		/** @type {Loader} */
+		var loader = {
+			getIds: function () {
+				var ids = [];
+				loader.load(function (id) {
+					ids.push(id);
+				});
+				return ids;
+			},
+			load: function (loadComponent, chainer) {
+				return loadComponentsInOrder(dependencyResolver, loadSet, loadComponent, chainer);
+			},
+		};
+
+		return loader;
+	}
+
+	return getLoader;
+})();
diff --git a/packages/astro-prism/tsconfig.json b/packages/astro-prism/tsconfig.json
index 17e08031358c..34c71757b6f0 100644
--- a/packages/astro-prism/tsconfig.json
+++ b/packages/astro-prism/tsconfig.json
@@ -3,6 +3,7 @@
   "include": ["src"],
   "compilerOptions": {
     "rootDir": "./src",
-    "outDir": "./dist"
+    "outDir": "./dist",
+    "types": ["vite/client"]
   }
 }
diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.js b/packages/integrations/cloudflare/test/astro-dev-platform.test.js
index 779d2a1b2a25..d5204fdc5cd4 100644
--- a/packages/integrations/cloudflare/test/astro-dev-platform.test.js
+++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.js
@@ -70,4 +70,15 @@ describe('AstroDevPlatform', () => {
 		// Verify the code block was rendered
 		assert.ok($('pre').length > 0, 'Code block should be rendered');
 	});
+
+	it('Prism component works in dev mode (no CommonJS module errors)', async () => {
+		const res = await fixture.fetch('/prism-test');
+		assert.equal(res.status, 200);
+		const html = await res.text();
+		const $ = cheerio.load(html);
+		// Verify the page rendered successfully with Prsim component
+		assert.equal($('h1').text(), 'Testing Prism Component');
+		// Verify the code block was rendered
+		assert.ok($('pre').length > 0, 'Code block should be rendered');
+	});
 });
diff --git a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/package.json b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/package.json
index 2c86b4ebd44f..8821ef6d3646 100644
--- a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/package.json
+++ b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/package.json
@@ -4,6 +4,7 @@
   "private": true,
   "dependencies": {
     "@astrojs/cloudflare": "workspace:*",
+    "@astrojs/prism": "workspace:*",
     "astro": "workspace:*"
   },
   "devDependencies": {
diff --git a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro
new file mode 100644
index 000000000000..6ca20bdc9038
--- /dev/null
+++ b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro
@@ -0,0 +1,12 @@
+---
+import { Prism } from '@astrojs/prism';
+---
+
+
+	Prism Component Test
+
+
+

Testing Prism Component

+ + + diff --git a/packages/integrations/markdoc/src/extensions/prism.ts b/packages/integrations/markdoc/src/extensions/prism.ts index 7215648712d9..05d546ceb3e2 100644 --- a/packages/integrations/markdoc/src/extensions/prism.ts +++ b/packages/integrations/markdoc/src/extensions/prism.ts @@ -7,8 +7,8 @@ export default function prism(): AstroMarkdocConfig { nodes: { fence: { attributes: Markdoc.nodes.fence.attributes!, - transform({ attributes: { language, content } }) { - const { html, classLanguage } = runHighlighterWithAstro(language, content); + async transform({ attributes: { language, content } }) { + const { html, classLanguage } = await runHighlighterWithAstro(language, content); // Use `unescapeHTML` to return `HTMLString` for Astro renderer to inline as HTML return unescapeHTML( diff --git a/packages/markdown/remark/src/rehype-prism.ts b/packages/markdown/remark/src/rehype-prism.ts index 096c4ab79100..0f32a22deca7 100644 --- a/packages/markdown/remark/src/rehype-prism.ts +++ b/packages/markdown/remark/src/rehype-prism.ts @@ -7,12 +7,10 @@ export const rehypePrism: Plugin<[string[]?], Root> = (excludeLangs) => { return async (tree) => { await highlightCodeBlocks( tree, - (code, language) => { - let { html, classLanguage } = runHighlighterWithAstro(language, code); + async (code, language) => { + let { html, classLanguage } = await runHighlighterWithAstro(language, code); - return Promise.resolve( - `
${html}
`, - ); + return `
${html}
`; }, excludeLangs, ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b49c2c26ef50..08289b6037d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4905,6 +4905,9 @@ importers: '@astrojs/cloudflare': specifier: workspace:* version: link:../../.. + '@astrojs/prism': + specifier: workspace:* + version: link:../../../../../astro-prism astro: specifier: workspace:* version: link:../../../../../astro From 8b7157cecc2993e98c7e465769adf7532a55a019 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 03:33:56 +0900 Subject: [PATCH 02/18] add vite as a devDependency --- packages/astro-prism/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/astro-prism/package.json b/packages/astro-prism/package.json index 49a8354535f6..6db828e7404a 100644 --- a/packages/astro-prism/package.json +++ b/packages/astro-prism/package.json @@ -42,7 +42,8 @@ }, "devDependencies": { "@types/prismjs": "1.26.6", - "astro-scripts": "workspace:*" + "astro-scripts": "workspace:*", + "vite": "^7.3.1" }, "engines": { "node": "^20.19.1 || >=22.12.0" From 0a5445d3be997110e0523e614cc571b621daf8e5 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 03:35:31 +0900 Subject: [PATCH 03/18] omg --- pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08289b6037d9..52e75eef6b92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -778,6 +778,9 @@ importers: astro-scripts: specifier: workspace:* version: link:../../scripts + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2) packages/astro-rss: dependencies: From bf6b5471939596d478e3a4b091925dc75d4f5075 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 03:51:40 +0900 Subject: [PATCH 04/18] fix knip error --- knip.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/knip.js b/knip.js index 70702de01bc7..4a4c9c974e71 100644 --- a/knip.js +++ b/knip.js @@ -54,6 +54,10 @@ export default { '@astrojs/cloudflare', ], }, + 'packages/astro-prism': { + // package.json#imports are not resolved at the moment + ignore: ['src/loadLanguages-workerd.ts', 'src/prism/**'], + }, 'packages/db': { entry: [testEntry, 'test/types/**/*'], }, From d57df0447392829c1f9c854ed23553568ed410bd Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 17:49:36 +0900 Subject: [PATCH 05/18] try replacing all static imports of prism with dynamic imports --- packages/astro-prism/src/highlighter.ts | 5 ++- .../astro-prism/src/loadLanguages-default.ts | 6 ++- .../astro-prism/src/loadLanguages-workerd.ts | 38 +++++++++++-------- .../test/astro-dev-platform.test.js | 2 +- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/astro-prism/src/highlighter.ts b/packages/astro-prism/src/highlighter.ts index 206b7b086a1e..51e6ae4316c2 100644 --- a/packages/astro-prism/src/highlighter.ts +++ b/packages/astro-prism/src/highlighter.ts @@ -1,10 +1,11 @@ -import Prism from 'prismjs'; -import loadLanguages from '#prism-loadLanguages'; +import { loadPrism, loadLanguages } from '#prism-loadLanguages'; import { addAstro } from './plugin.js'; const languageMap = new Map([['ts', 'typescript']]); export async function runHighlighterWithAstro(lang: string | undefined, code: string) { + const Prism = await loadPrism(); + if (!lang) { lang = 'plaintext'; } diff --git a/packages/astro-prism/src/loadLanguages-default.ts b/packages/astro-prism/src/loadLanguages-default.ts index bfe3d6469787..e57baf1cebe7 100644 --- a/packages/astro-prism/src/loadLanguages-default.ts +++ b/packages/astro-prism/src/loadLanguages-default.ts @@ -1,5 +1,9 @@ +import Prism from 'prismjs'; import prismLoadLanguages from 'prismjs/components/index.js'; -export default async function loadLanguages(languages: string | string[]) { +export async function loadPrism() { + return Prism; +} +export async function loadLanguages(languages: string | string[]) { return prismLoadLanguages(languages); } diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts index 0282fb6b344a..41ba43dc40f1 100644 --- a/packages/astro-prism/src/loadLanguages-workerd.ts +++ b/packages/astro-prism/src/loadLanguages-workerd.ts @@ -1,14 +1,11 @@ // This implementation was based from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components/index.js -import Prism from 'prismjs'; -import { components } from './prism/components.js'; -import { getLoader } from './prism/dependencies.js'; const prismLanguageFiles = import.meta.glob('../node_modules/prismjs/components/prism-*.js'); // Since Prism language files are written assuming the Prism instance is defined // as a global variable, we will temporarily set the Prism instance globally. -function setPrismAsGlobal() { - globalThis.Prism = Prism; +function setPrismAsGlobal(prism: typeof import('prismjs')) { + globalThis.Prism = prism; return () => { // @ts-expect-error globalThis type @@ -16,12 +13,22 @@ function setPrismAsGlobal() { }; } +let cache: typeof import('prismjs') | undefined = undefined; + +export async function loadPrism() { + if (!cache) { + ({ default: cache } = await import('prismjs')); + } + + return cache; +} + /** * The set of all languages which have been loaded using the below function. * * @type {Set} */ -const loadedLanguages = new Set(); +const loadedLanguages = new Set(); /** * Loads the given languages and adds them to the current Prism instance. @@ -31,11 +38,12 @@ const loadedLanguages = new Set(); * @param {string|string[]} [languages] * @returns {Promise} */ -export default async function loadLanguages(languages: string | string[]) { - const cleanUp = setPrismAsGlobal(); +export async function loadLanguages(languages: string | string[]) { + const Prism = await loadPrism(); + const { default: components } = await import('prismjs/components.js'); + const { default: getLoader } = await import('prismjs/dependencies.js'); - let resolve: VoidFunction; - const promise = new Promise((r) => (resolve = r)); + const cleanUp = setPrismAsGlobal(Prism); if (languages === undefined) { languages = Object.keys(components.languages).filter((l) => l !== 'meta'); @@ -47,8 +55,7 @@ export default async function loadLanguages(languages: string | string[]) { // we don't need to validate the ids because `getLoader` will ignore invalid ones const loaded = [...loadedLanguages, ...Object.keys(Prism.languages)]; - // @ts-expect-error `load` arguments type - getLoader(components, languages, loaded).load(async (lang: string) => { + await getLoader(components, languages, loaded).load(async (lang: string) => { if (!(lang in components.languages)) { if (!loadLanguages.silent) { console.warn('Language does not exist: ' + lang); @@ -61,13 +68,14 @@ export default async function loadLanguages(languages: string | string[]) { // remove from Prism delete Prism.languages[lang]; - await prismLanguageFiles[pathToLanguage](); + if (Object.hasOwn(prismLanguageFiles, pathToLanguage)) { + await prismLanguageFiles[pathToLanguage](); + } loadedLanguages.add(lang); - resolve(); }); - return promise.then(cleanUp); + cleanUp(); } /** diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.js b/packages/integrations/cloudflare/test/astro-dev-platform.test.js index d5204fdc5cd4..a35111225e33 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.js +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.js @@ -76,7 +76,7 @@ describe('AstroDevPlatform', () => { assert.equal(res.status, 200); const html = await res.text(); const $ = cheerio.load(html); - // Verify the page rendered successfully with Prsim component + // Verify the page rendered successfully with Prism component assert.equal($('h1').text(), 'Testing Prism Component'); // Verify the code block was rendered assert.ok($('pre').length > 0, 'Code block should be rendered'); From fe8ec4f34fbb081cd79bbdc8b203a10abf4b9fe1 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 23:05:48 +0900 Subject: [PATCH 06/18] remove unnecessary files --- knip.js | 4 - packages/astro-prism/src/prism/components.ts | 742 ------------------ .../astro-prism/src/prism/dependencies.ts | 460 ----------- 3 files changed, 1206 deletions(-) delete mode 100644 packages/astro-prism/src/prism/components.ts delete mode 100644 packages/astro-prism/src/prism/dependencies.ts diff --git a/knip.js b/knip.js index 4a4c9c974e71..70702de01bc7 100644 --- a/knip.js +++ b/knip.js @@ -54,10 +54,6 @@ export default { '@astrojs/cloudflare', ], }, - 'packages/astro-prism': { - // package.json#imports are not resolved at the moment - ignore: ['src/loadLanguages-workerd.ts', 'src/prism/**'], - }, 'packages/db': { entry: [testEntry, 'test/types/**/*'], }, diff --git a/packages/astro-prism/src/prism/components.ts b/packages/astro-prism/src/prism/components.ts deleted file mode 100644 index 68aa996eb446..000000000000 --- a/packages/astro-prism/src/prism/components.ts +++ /dev/null @@ -1,742 +0,0 @@ -// This implementation was ported from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components.js -// biome-ignore-all lint: Ported from the original source as-is -// eslint-disable-next-line no-var -export var components = { - core: { meta: { path: 'components/prism-core.js', option: 'mandatory' }, core: 'Core' }, - themes: { - meta: { path: 'themes/{id}.css', link: 'index.html?theme={id}', exclusive: true }, - prism: { title: 'Default', option: 'default' }, - 'prism-dark': 'Dark', - 'prism-funky': 'Funky', - 'prism-okaidia': { title: 'Okaidia', owner: 'ocodia' }, - 'prism-twilight': { title: 'Twilight', owner: 'remybach' }, - 'prism-coy': { title: 'Coy', owner: 'tshedor' }, - 'prism-solarizedlight': { title: 'Solarized Light', owner: 'hectormatos2011 ' }, - 'prism-tomorrow': { title: 'Tomorrow Night', owner: 'Rosey' }, - }, - languages: { - meta: { - path: 'components/prism-{id}', - noCSS: true, - examplesPath: 'examples/prism-{id}', - addCheckAll: true, - }, - markup: { - title: 'Markup', - alias: ['html', 'xml', 'svg', 'mathml', 'ssml', 'atom', 'rss'], - aliasTitles: { - html: 'HTML', - xml: 'XML', - svg: 'SVG', - mathml: 'MathML', - ssml: 'SSML', - atom: 'Atom', - rss: 'RSS', - }, - option: 'default', - }, - css: { title: 'CSS', option: 'default', modify: 'markup' }, - clike: { title: 'C-like', option: 'default' }, - javascript: { - title: 'JavaScript', - require: 'clike', - modify: 'markup', - optional: 'regex', - alias: 'js', - option: 'default', - }, - abap: { title: 'ABAP', owner: 'dellagustin' }, - abnf: { title: 'ABNF', owner: 'RunDevelopment' }, - actionscript: { - title: 'ActionScript', - require: 'javascript', - modify: 'markup', - owner: 'Golmote', - }, - ada: { title: 'Ada', owner: 'Lucretia' }, - agda: { title: 'Agda', owner: 'xy-ren' }, - al: { title: 'AL', owner: 'RunDevelopment' }, - antlr4: { title: 'ANTLR4', alias: 'g4', owner: 'RunDevelopment' }, - apacheconf: { title: 'Apache Configuration', owner: 'GuiTeK' }, - apex: { title: 'Apex', require: ['clike', 'sql'], owner: 'RunDevelopment' }, - apl: { title: 'APL', owner: 'ngn' }, - applescript: { title: 'AppleScript', owner: 'Golmote' }, - aql: { title: 'AQL', owner: 'RunDevelopment' }, - arduino: { title: 'Arduino', require: 'cpp', alias: 'ino', owner: 'dkern' }, - arff: { title: 'ARFF', owner: 'Golmote' }, - armasm: { title: 'ARM Assembly', alias: 'arm-asm', owner: 'RunDevelopment' }, - arturo: { - title: 'Arturo', - alias: 'art', - optional: ['bash', 'css', 'javascript', 'markup', 'markdown', 'sql'], - owner: 'drkameleon', - }, - asciidoc: { alias: 'adoc', title: 'AsciiDoc', owner: 'Golmote' }, - aspnet: { title: 'ASP.NET (C#)', require: ['markup', 'csharp'], owner: 'nauzilus' }, - asm6502: { title: '6502 Assembly', owner: 'kzurawel' }, - asmatmel: { title: 'Atmel AVR Assembly', owner: 'cerkit' }, - autohotkey: { title: 'AutoHotkey', owner: 'aviaryan' }, - autoit: { title: 'AutoIt', owner: 'Golmote' }, - avisynth: { title: 'AviSynth', alias: 'avs', owner: 'Zinfidel' }, - 'avro-idl': { title: 'Avro IDL', alias: 'avdl', owner: 'RunDevelopment' }, - awk: { title: 'AWK', alias: 'gawk', aliasTitles: { gawk: 'GAWK' }, owner: 'RunDevelopment' }, - bash: { - title: 'Bash', - alias: ['sh', 'shell'], - aliasTitles: { sh: 'Shell', shell: 'Shell' }, - owner: 'zeitgeist87', - }, - basic: { title: 'BASIC', owner: 'Golmote' }, - batch: { title: 'Batch', owner: 'Golmote' }, - bbcode: { - title: 'BBcode', - alias: 'shortcode', - aliasTitles: { shortcode: 'Shortcode' }, - owner: 'RunDevelopment', - }, - bbj: { title: 'BBj', owner: 'hyyan' }, - bicep: { title: 'Bicep', owner: 'johnnyreilly' }, - birb: { title: 'Birb', require: 'clike', owner: 'Calamity210' }, - bison: { title: 'Bison', require: 'c', owner: 'Golmote' }, - bnf: { title: 'BNF', alias: 'rbnf', aliasTitles: { rbnf: 'RBNF' }, owner: 'RunDevelopment' }, - bqn: { title: 'BQN', owner: 'yewscion' }, - brainfuck: { title: 'Brainfuck', owner: 'Golmote' }, - brightscript: { title: 'BrightScript', owner: 'RunDevelopment' }, - bro: { title: 'Bro', owner: 'wayward710' }, - bsl: { - title: 'BSL (1C:Enterprise)', - alias: 'oscript', - aliasTitles: { oscript: 'OneScript' }, - owner: 'Diversus23', - }, - c: { title: 'C', require: 'clike', owner: 'zeitgeist87' }, - csharp: { title: 'C#', require: 'clike', alias: ['cs', 'dotnet'], owner: 'mvalipour' }, - cpp: { title: 'C++', require: 'c', owner: 'zeitgeist87' }, - cfscript: { title: 'CFScript', require: 'clike', alias: 'cfc', owner: 'mjclemente' }, - chaiscript: { title: 'ChaiScript', require: ['clike', 'cpp'], owner: 'RunDevelopment' }, - cil: { title: 'CIL', owner: 'sbrl' }, - cilkc: { title: 'Cilk/C', require: 'c', alias: 'cilk-c', owner: 'OpenCilk' }, - cilkcpp: { title: 'Cilk/C++', require: 'cpp', alias: ['cilk-cpp', 'cilk'], owner: 'OpenCilk' }, - clojure: { title: 'Clojure', owner: 'troglotit' }, - cmake: { title: 'CMake', owner: 'mjrogozinski' }, - cobol: { title: 'COBOL', owner: 'RunDevelopment' }, - coffeescript: { - title: 'CoffeeScript', - require: 'javascript', - alias: 'coffee', - owner: 'R-osey', - }, - concurnas: { title: 'Concurnas', alias: 'conc', owner: 'jasontatton' }, - csp: { title: 'Content-Security-Policy', owner: 'ScottHelme' }, - cooklang: { title: 'Cooklang', owner: 'ahue' }, - coq: { title: 'Coq', owner: 'RunDevelopment' }, - crystal: { title: 'Crystal', require: 'ruby', owner: 'MakeNowJust' }, - 'css-extras': { title: 'CSS Extras', require: 'css', modify: 'css', owner: 'milesj' }, - csv: { title: 'CSV', owner: 'RunDevelopment' }, - cue: { title: 'CUE', owner: 'RunDevelopment' }, - cypher: { title: 'Cypher', owner: 'RunDevelopment' }, - d: { title: 'D', require: 'clike', owner: 'Golmote' }, - dart: { title: 'Dart', require: 'clike', owner: 'Golmote' }, - dataweave: { title: 'DataWeave', owner: 'machaval' }, - dax: { title: 'DAX', owner: 'peterbud' }, - dhall: { title: 'Dhall', owner: 'RunDevelopment' }, - diff: { title: 'Diff', owner: 'uranusjr' }, - django: { - title: 'Django/Jinja2', - require: 'markup-templating', - alias: 'jinja2', - owner: 'romanvm', - }, - 'dns-zone-file': { title: 'DNS zone file', owner: 'RunDevelopment', alias: 'dns-zone' }, - docker: { title: 'Docker', alias: 'dockerfile', owner: 'JustinBeckwith' }, - dot: { title: 'DOT (Graphviz)', alias: 'gv', optional: 'markup', owner: 'RunDevelopment' }, - ebnf: { title: 'EBNF', owner: 'RunDevelopment' }, - editorconfig: { title: 'EditorConfig', owner: 'osipxd' }, - eiffel: { title: 'Eiffel', owner: 'Conaclos' }, - ejs: { - title: 'EJS', - require: ['javascript', 'markup-templating'], - owner: 'RunDevelopment', - alias: 'eta', - aliasTitles: { eta: 'Eta' }, - }, - elixir: { title: 'Elixir', owner: 'Golmote' }, - elm: { title: 'Elm', owner: 'zwilias' }, - etlua: { - title: 'Embedded Lua templating', - require: ['lua', 'markup-templating'], - owner: 'RunDevelopment', - }, - erb: { title: 'ERB', require: ['ruby', 'markup-templating'], owner: 'Golmote' }, - erlang: { title: 'Erlang', owner: 'Golmote' }, - 'excel-formula': { title: 'Excel Formula', alias: ['xlsx', 'xls'], owner: 'RunDevelopment' }, - fsharp: { title: 'F#', require: 'clike', owner: 'simonreynolds7' }, - factor: { title: 'Factor', owner: 'catb0t' }, - false: { title: 'False', owner: 'edukisto' }, - 'firestore-security-rules': { - title: 'Firestore security rules', - require: 'clike', - owner: 'RunDevelopment', - }, - flow: { title: 'Flow', require: 'javascript', owner: 'Golmote' }, - fortran: { title: 'Fortran', owner: 'Golmote' }, - ftl: { - title: 'FreeMarker Template Language', - require: 'markup-templating', - owner: 'RunDevelopment', - }, - gml: { - title: 'GameMaker Language', - alias: 'gamemakerlanguage', - require: 'clike', - owner: 'LiarOnce', - }, - gap: { title: 'GAP (CAS)', owner: 'RunDevelopment' }, - gcode: { title: 'G-code', owner: 'RunDevelopment' }, - gdscript: { title: 'GDScript', owner: 'RunDevelopment' }, - gedcom: { title: 'GEDCOM', owner: 'Golmote' }, - gettext: { title: 'gettext', alias: 'po', owner: 'RunDevelopment' }, - gherkin: { title: 'Gherkin', owner: 'hason' }, - git: { title: 'Git', owner: 'lgiraudel' }, - glsl: { title: 'GLSL', require: 'c', owner: 'Golmote' }, - gn: { title: 'GN', alias: 'gni', owner: 'RunDevelopment' }, - 'linker-script': { title: 'GNU Linker Script', alias: 'ld', owner: 'RunDevelopment' }, - go: { title: 'Go', require: 'clike', owner: 'arnehormann' }, - 'go-module': { title: 'Go module', alias: 'go-mod', owner: 'RunDevelopment' }, - gradle: { title: 'Gradle', require: 'clike', owner: 'zeabdelkhalek-badido18' }, - graphql: { title: 'GraphQL', optional: 'markdown', owner: 'Golmote' }, - groovy: { title: 'Groovy', require: 'clike', owner: 'robfletcher' }, - haml: { - title: 'Haml', - require: 'ruby', - optional: [ - 'css', - 'css-extras', - 'coffeescript', - 'erb', - 'javascript', - 'less', - 'markdown', - 'scss', - 'textile', - ], - owner: 'Golmote', - }, - handlebars: { - title: 'Handlebars', - require: 'markup-templating', - alias: ['hbs', 'mustache'], - aliasTitles: { mustache: 'Mustache' }, - owner: 'Golmote', - }, - haskell: { title: 'Haskell', alias: 'hs', owner: 'bholst' }, - haxe: { title: 'Haxe', require: 'clike', optional: 'regex', owner: 'Golmote' }, - hcl: { title: 'HCL', owner: 'outsideris' }, - hlsl: { title: 'HLSL', require: 'c', owner: 'RunDevelopment' }, - hoon: { title: 'Hoon', owner: 'matildepark' }, - http: { - title: 'HTTP', - optional: ['csp', 'css', 'hpkp', 'hsts', 'javascript', 'json', 'markup', 'uri'], - owner: 'danielgtaylor', - }, - hpkp: { title: 'HTTP Public-Key-Pins', owner: 'ScottHelme' }, - hsts: { title: 'HTTP Strict-Transport-Security', owner: 'ScottHelme' }, - ichigojam: { title: 'IchigoJam', owner: 'BlueCocoa' }, - icon: { title: 'Icon', owner: 'Golmote' }, - 'icu-message-format': { title: 'ICU Message Format', owner: 'RunDevelopment' }, - idris: { title: 'Idris', alias: 'idr', owner: 'KeenS', require: 'haskell' }, - ignore: { - title: '.ignore', - owner: 'osipxd', - alias: ['gitignore', 'hgignore', 'npmignore'], - aliasTitles: { gitignore: '.gitignore', hgignore: '.hgignore', npmignore: '.npmignore' }, - }, - inform7: { title: 'Inform 7', owner: 'Golmote' }, - ini: { title: 'Ini', owner: 'aviaryan' }, - io: { title: 'Io', owner: 'AlesTsurko' }, - j: { title: 'J', owner: 'Golmote' }, - java: { title: 'Java', require: 'clike', owner: 'sherblot' }, - javadoc: { - title: 'JavaDoc', - require: ['markup', 'java', 'javadoclike'], - modify: 'java', - optional: 'scala', - owner: 'RunDevelopment', - }, - javadoclike: { - title: 'JavaDoc-like', - modify: ['java', 'javascript', 'php'], - owner: 'RunDevelopment', - }, - javastacktrace: { title: 'Java stack trace', owner: 'RunDevelopment' }, - jexl: { title: 'Jexl', owner: 'czosel' }, - jolie: { title: 'Jolie', require: 'clike', owner: 'thesave' }, - jq: { title: 'JQ', owner: 'RunDevelopment' }, - jsdoc: { - title: 'JSDoc', - require: ['javascript', 'javadoclike', 'typescript'], - modify: 'javascript', - optional: ['actionscript', 'coffeescript'], - owner: 'RunDevelopment', - }, - 'js-extras': { - title: 'JS Extras', - require: 'javascript', - modify: 'javascript', - optional: ['actionscript', 'coffeescript', 'flow', 'n4js', 'typescript'], - owner: 'RunDevelopment', - }, - json: { - title: 'JSON', - alias: 'webmanifest', - aliasTitles: { webmanifest: 'Web App Manifest' }, - owner: 'CupOfTea696', - }, - json5: { title: 'JSON5', require: 'json', owner: 'RunDevelopment' }, - jsonp: { title: 'JSONP', require: 'json', owner: 'RunDevelopment' }, - jsstacktrace: { title: 'JS stack trace', owner: 'sbrl' }, - 'js-templates': { - title: 'JS Templates', - require: 'javascript', - modify: 'javascript', - optional: ['css', 'css-extras', 'graphql', 'markdown', 'markup', 'sql'], - owner: 'RunDevelopment', - }, - julia: { title: 'Julia', owner: 'cdagnino' }, - keepalived: { title: 'Keepalived Configure', owner: 'dev-itsheng' }, - keyman: { title: 'Keyman', owner: 'mcdurdin' }, - kotlin: { - title: 'Kotlin', - alias: ['kt', 'kts'], - aliasTitles: { kts: 'Kotlin Script' }, - require: 'clike', - owner: 'Golmote', - }, - kumir: { title: 'KuMir (КуМир)', alias: 'kum', owner: 'edukisto' }, - kusto: { title: 'Kusto', owner: 'RunDevelopment' }, - latex: { - title: 'LaTeX', - alias: ['tex', 'context'], - aliasTitles: { tex: 'TeX', context: 'ConTeXt' }, - owner: 'japborst', - }, - latte: { title: 'Latte', require: ['clike', 'markup-templating', 'php'], owner: 'nette' }, - less: { title: 'Less', require: 'css', optional: 'css-extras', owner: 'Golmote' }, - lilypond: { title: 'LilyPond', require: 'scheme', alias: 'ly', owner: 'RunDevelopment' }, - liquid: { title: 'Liquid', require: 'markup-templating', owner: 'cinhtau' }, - lisp: { title: 'Lisp', alias: ['emacs', 'elisp', 'emacs-lisp'], owner: 'JuanCaicedo' }, - livescript: { title: 'LiveScript', owner: 'Golmote' }, - llvm: { title: 'LLVM IR', owner: 'porglezomp' }, - log: { title: 'Log file', optional: 'javastacktrace', owner: 'RunDevelopment' }, - lolcode: { title: 'LOLCODE', owner: 'Golmote' }, - lua: { title: 'Lua', owner: 'Golmote' }, - magma: { title: 'Magma (CAS)', owner: 'RunDevelopment' }, - makefile: { title: 'Makefile', owner: 'Golmote' }, - markdown: { - title: 'Markdown', - require: 'markup', - optional: 'yaml', - alias: 'md', - owner: 'Golmote', - }, - 'markup-templating': { title: 'Markup templating', require: 'markup', owner: 'Golmote' }, - mata: { title: 'Mata', owner: 'RunDevelopment' }, - matlab: { title: 'MATLAB', owner: 'Golmote' }, - maxscript: { title: 'MAXScript', owner: 'RunDevelopment' }, - mel: { title: 'MEL', owner: 'Golmote' }, - mermaid: { title: 'Mermaid', owner: 'RunDevelopment' }, - metafont: { title: 'METAFONT', owner: 'LaeriExNihilo' }, - mizar: { title: 'Mizar', owner: 'Golmote' }, - mongodb: { title: 'MongoDB', owner: 'airs0urce', require: 'javascript' }, - monkey: { title: 'Monkey', owner: 'Golmote' }, - moonscript: { title: 'MoonScript', alias: 'moon', owner: 'RunDevelopment' }, - n1ql: { title: 'N1QL', owner: 'TMWilds' }, - n4js: { - title: 'N4JS', - require: 'javascript', - optional: 'jsdoc', - alias: 'n4jsd', - owner: 'bsmith-n4', - }, - 'nand2tetris-hdl': { title: 'Nand To Tetris HDL', owner: 'stephanmax' }, - naniscript: { title: 'Naninovel Script', owner: 'Elringus', alias: 'nani' }, - nasm: { title: 'NASM', owner: 'rbmj' }, - neon: { title: 'NEON', owner: 'nette' }, - nevod: { title: 'Nevod', owner: 'nezaboodka' }, - nginx: { title: 'nginx', owner: 'volado' }, - nim: { title: 'Nim', owner: 'Golmote' }, - nix: { title: 'Nix', owner: 'Golmote' }, - nsis: { title: 'NSIS', owner: 'idleberg' }, - objectivec: { title: 'Objective-C', require: 'c', alias: 'objc', owner: 'uranusjr' }, - ocaml: { title: 'OCaml', owner: 'Golmote' }, - odin: { title: 'Odin', owner: 'edukisto' }, - opencl: { title: 'OpenCL', require: 'c', modify: ['c', 'cpp'], owner: 'Milania1' }, - openqasm: { title: 'OpenQasm', alias: 'qasm', owner: 'RunDevelopment' }, - oz: { title: 'Oz', owner: 'Golmote' }, - parigp: { title: 'PARI/GP', owner: 'Golmote' }, - parser: { title: 'Parser', require: 'markup', owner: 'Golmote' }, - pascal: { - title: 'Pascal', - alias: 'objectpascal', - aliasTitles: { objectpascal: 'Object Pascal' }, - owner: 'Golmote', - }, - pascaligo: { title: 'Pascaligo', owner: 'DefinitelyNotAGoat' }, - psl: { title: 'PATROL Scripting Language', owner: 'bertysentry' }, - pcaxis: { title: 'PC-Axis', alias: 'px', owner: 'RunDevelopment' }, - peoplecode: { title: 'PeopleCode', alias: 'pcode', owner: 'RunDevelopment' }, - perl: { title: 'Perl', owner: 'Golmote' }, - php: { title: 'PHP', require: 'markup-templating', owner: 'milesj' }, - phpdoc: { - title: 'PHPDoc', - require: ['php', 'javadoclike'], - modify: 'php', - owner: 'RunDevelopment', - }, - 'php-extras': { title: 'PHP Extras', require: 'php', modify: 'php', owner: 'milesj' }, - 'plant-uml': { title: 'PlantUML', alias: 'plantuml', owner: 'RunDevelopment' }, - plsql: { title: 'PL/SQL', require: 'sql', owner: 'Golmote' }, - powerquery: { title: 'PowerQuery', alias: ['pq', 'mscript'], owner: 'peterbud' }, - powershell: { title: 'PowerShell', owner: 'nauzilus' }, - processing: { title: 'Processing', require: 'clike', owner: 'Golmote' }, - prolog: { title: 'Prolog', owner: 'Golmote' }, - promql: { title: 'PromQL', owner: 'arendjr' }, - properties: { title: '.properties', owner: 'Golmote' }, - protobuf: { title: 'Protocol Buffers', require: 'clike', owner: 'just-boris' }, - pug: { - title: 'Pug', - require: ['markup', 'javascript'], - optional: [ - 'coffeescript', - 'ejs', - 'handlebars', - 'less', - 'livescript', - 'markdown', - 'scss', - 'stylus', - 'twig', - ], - owner: 'Golmote', - }, - puppet: { title: 'Puppet', owner: 'Golmote' }, - pure: { title: 'Pure', optional: ['c', 'cpp', 'fortran'], owner: 'Golmote' }, - purebasic: { title: 'PureBasic', require: 'clike', alias: 'pbfasm', owner: 'HeX0R101' }, - purescript: { - title: 'PureScript', - require: 'haskell', - alias: 'purs', - owner: 'sriharshachilakapati', - }, - python: { title: 'Python', alias: 'py', owner: 'multipetros' }, - qsharp: { title: 'Q#', require: 'clike', alias: 'qs', owner: 'fedonman' }, - q: { title: 'Q (kdb+ database)', owner: 'Golmote' }, - qml: { title: 'QML', require: 'javascript', owner: 'RunDevelopment' }, - qore: { title: 'Qore', require: 'clike', owner: 'temnroegg' }, - r: { title: 'R', owner: 'Golmote' }, - racket: { title: 'Racket', require: 'scheme', alias: 'rkt', owner: 'RunDevelopment' }, - cshtml: { - title: 'Razor C#', - alias: 'razor', - require: ['markup', 'csharp'], - optional: ['css', 'css-extras', 'javascript', 'js-extras'], - owner: 'RunDevelopment', - }, - jsx: { - title: 'React JSX', - require: ['markup', 'javascript'], - optional: ['jsdoc', 'js-extras', 'js-templates'], - owner: 'vkbansal', - }, - tsx: { title: 'React TSX', require: ['jsx', 'typescript'] }, - reason: { title: 'Reason', require: 'clike', owner: 'Golmote' }, - regex: { title: 'Regex', owner: 'RunDevelopment' }, - rego: { title: 'Rego', owner: 'JordanSh' }, - renpy: { title: "Ren'py", alias: 'rpy', owner: 'HyuchiaDiego' }, - rescript: { title: 'ReScript', alias: 'res', owner: 'vmarcosp' }, - rest: { title: 'reST (reStructuredText)', owner: 'Golmote' }, - rip: { title: 'Rip', owner: 'ravinggenius' }, - roboconf: { title: 'Roboconf', owner: 'Golmote' }, - robotframework: { title: 'Robot Framework', alias: 'robot', owner: 'RunDevelopment' }, - ruby: { title: 'Ruby', require: 'clike', alias: 'rb', owner: 'samflores' }, - rust: { title: 'Rust', owner: 'Golmote' }, - sas: { title: 'SAS', optional: ['groovy', 'lua', 'sql'], owner: 'Golmote' }, - sass: { title: 'Sass (Sass)', require: 'css', optional: 'css-extras', owner: 'Golmote' }, - scss: { title: 'Sass (SCSS)', require: 'css', optional: 'css-extras', owner: 'MoOx' }, - scala: { title: 'Scala', require: 'java', owner: 'jozic' }, - scheme: { title: 'Scheme', owner: 'bacchus123' }, - 'shell-session': { - title: 'Shell session', - require: 'bash', - alias: ['sh-session', 'shellsession'], - owner: 'RunDevelopment', - }, - smali: { title: 'Smali', owner: 'RunDevelopment' }, - smalltalk: { title: 'Smalltalk', owner: 'Golmote' }, - smarty: { title: 'Smarty', require: 'markup-templating', optional: 'php', owner: 'Golmote' }, - sml: { - title: 'SML', - alias: 'smlnj', - aliasTitles: { smlnj: 'SML/NJ' }, - owner: 'RunDevelopment', - }, - solidity: { title: 'Solidity (Ethereum)', alias: 'sol', require: 'clike', owner: 'glachaud' }, - 'solution-file': { title: 'Solution file', alias: 'sln', owner: 'RunDevelopment' }, - soy: { title: 'Soy (Closure Template)', require: 'markup-templating', owner: 'Golmote' }, - sparql: { title: 'SPARQL', require: 'turtle', owner: 'Triply-Dev', alias: 'rq' }, - 'splunk-spl': { title: 'Splunk SPL', owner: 'RunDevelopment' }, - sqf: { title: 'SQF: Status Quo Function (Arma 3)', require: 'clike', owner: 'RunDevelopment' }, - sql: { title: 'SQL', owner: 'multipetros' }, - squirrel: { title: 'Squirrel', require: 'clike', owner: 'RunDevelopment' }, - stan: { title: 'Stan', owner: 'RunDevelopment' }, - stata: { title: 'Stata Ado', require: ['mata', 'java', 'python'], owner: 'RunDevelopment' }, - iecst: { title: 'Structured Text (IEC 61131-3)', owner: 'serhioromano' }, - stylus: { title: 'Stylus', owner: 'vkbansal' }, - supercollider: { title: 'SuperCollider', alias: 'sclang', owner: 'RunDevelopment' }, - swift: { title: 'Swift', owner: 'chrischares' }, - systemd: { title: 'Systemd configuration file', owner: 'RunDevelopment' }, - 't4-templating': { title: 'T4 templating', owner: 'RunDevelopment' }, - 't4-cs': { - title: 'T4 Text Templates (C#)', - require: ['t4-templating', 'csharp'], - alias: 't4', - owner: 'RunDevelopment', - }, - 't4-vb': { - title: 'T4 Text Templates (VB)', - require: ['t4-templating', 'vbnet'], - owner: 'RunDevelopment', - }, - tap: { title: 'TAP', owner: 'isaacs', require: 'yaml' }, - tcl: { title: 'Tcl', owner: 'PeterChaplin' }, - tt2: { title: 'Template Toolkit 2', require: ['clike', 'markup-templating'], owner: 'gflohr' }, - textile: { title: 'Textile', require: 'markup', optional: 'css', owner: 'Golmote' }, - toml: { title: 'TOML', owner: 'RunDevelopment' }, - tremor: { - title: 'Tremor', - alias: ['trickle', 'troy'], - owner: 'darach', - aliasTitles: { trickle: 'trickle', troy: 'troy' }, - }, - turtle: { title: 'Turtle', alias: 'trig', aliasTitles: { trig: 'TriG' }, owner: 'jakubklimek' }, - twig: { title: 'Twig', require: 'markup-templating', owner: 'brandonkelly' }, - typescript: { - title: 'TypeScript', - require: 'javascript', - optional: 'js-templates', - alias: 'ts', - owner: 'vkbansal', - }, - typoscript: { - title: 'TypoScript', - alias: 'tsconfig', - aliasTitles: { tsconfig: 'TSConfig' }, - owner: 'dkern', - }, - unrealscript: { title: 'UnrealScript', alias: ['uscript', 'uc'], owner: 'RunDevelopment' }, - uorazor: { title: 'UO Razor Script', owner: 'jaseowns' }, - uri: { title: 'URI', alias: 'url', aliasTitles: { url: 'URL' }, owner: 'RunDevelopment' }, - v: { title: 'V', require: 'clike', owner: 'taggon' }, - vala: { title: 'Vala', require: 'clike', optional: 'regex', owner: 'TemplarVolk' }, - vbnet: { title: 'VB.Net', require: 'basic', owner: 'Bigsby' }, - velocity: { title: 'Velocity', require: 'markup', owner: 'Golmote' }, - verilog: { title: 'Verilog', owner: 'a-rey' }, - vhdl: { title: 'VHDL', owner: 'a-rey' }, - vim: { title: 'vim', owner: 'westonganger' }, - 'visual-basic': { - title: 'Visual Basic', - alias: ['vb', 'vba'], - aliasTitles: { vba: 'VBA' }, - owner: 'Golmote', - }, - warpscript: { title: 'WarpScript', owner: 'RunDevelopment' }, - wasm: { title: 'WebAssembly', owner: 'Golmote' }, - 'web-idl': { title: 'Web IDL', alias: 'webidl', owner: 'RunDevelopment' }, - wgsl: { title: 'WGSL', owner: 'Dr4gonthree' }, - wiki: { title: 'Wiki markup', require: 'markup', owner: 'Golmote' }, - wolfram: { - title: 'Wolfram language', - alias: ['mathematica', 'nb', 'wl'], - aliasTitles: { mathematica: 'Mathematica', nb: 'Mathematica Notebook' }, - owner: 'msollami', - }, - wren: { title: 'Wren', owner: 'clsource' }, - xeora: { - title: 'Xeora', - require: 'markup', - alias: 'xeoracube', - aliasTitles: { xeoracube: 'XeoraCube' }, - owner: 'freakmaxi', - }, - 'xml-doc': { - title: 'XML doc (.net)', - require: 'markup', - modify: ['csharp', 'fsharp', 'vbnet'], - owner: 'RunDevelopment', - }, - xojo: { title: 'Xojo (REALbasic)', owner: 'Golmote' }, - xquery: { title: 'XQuery', require: 'markup', owner: 'Golmote' }, - yaml: { title: 'YAML', alias: 'yml', owner: 'hason' }, - yang: { title: 'YANG', owner: 'RunDevelopment' }, - zig: { title: 'Zig', owner: 'RunDevelopment' }, - }, - plugins: { - meta: { path: 'plugins/{id}/prism-{id}', link: 'plugins/{id}/' }, - 'line-highlight': { - title: 'Line Highlight', - description: 'Highlights specific lines and/or line ranges.', - }, - 'line-numbers': { - title: 'Line Numbers', - description: 'Line number at the beginning of code lines.', - owner: 'kuba-kubula', - }, - 'show-invisibles': { - title: 'Show Invisibles', - description: 'Show hidden characters such as tabs and line breaks.', - optional: ['autolinker', 'data-uri-highlight'], - }, - autolinker: { - title: 'Autolinker', - description: - 'Converts URLs and emails in code to clickable links. Parses Markdown links in comments.', - }, - wpd: { - title: 'WebPlatform Docs', - description: - 'Makes tokens link to WebPlatform.org documentation. The links open in a new tab.', - }, - 'custom-class': { - title: 'Custom Class', - description: - "This plugin allows you to prefix Prism's default classes (.comment can become .namespace--comment) or replace them with your defined ones (like .editor__comment). You can even add new classes.", - owner: 'dvkndn', - noCSS: true, - }, - 'file-highlight': { - title: 'File Highlight', - description: - 'Fetch external files and highlight them with Prism. Used on the Prism website itself.', - noCSS: true, - }, - 'show-language': { - title: 'Show Language', - description: - 'Display the highlighted language in code blocks (inline code does not show the label).', - owner: 'nauzilus', - noCSS: true, - require: 'toolbar', - }, - 'jsonp-highlight': { - title: 'JSONP Highlight', - description: - 'Fetch content with JSONP and highlight some interesting content (e.g. GitHub/Gists or Bitbucket API).', - noCSS: true, - owner: 'nauzilus', - }, - 'highlight-keywords': { - title: 'Highlight Keywords', - description: 'Adds special CSS classes for each keyword for fine-grained highlighting.', - owner: 'vkbansal', - noCSS: true, - }, - 'remove-initial-line-feed': { - title: 'Remove initial line feed', - description: 'Removes the initial line feed in code blocks.', - owner: 'Golmote', - noCSS: true, - }, - 'inline-color': { - title: 'Inline color', - description: 'Adds a small inline preview for colors in style sheets.', - require: 'css-extras', - owner: 'RunDevelopment', - }, - previewers: { - title: 'Previewers', - description: 'Previewers for angles, colors, gradients, easing and time.', - require: 'css-extras', - owner: 'Golmote', - }, - autoloader: { - title: 'Autoloader', - description: 'Automatically loads the needed languages to highlight the code blocks.', - owner: 'Golmote', - noCSS: true, - }, - 'keep-markup': { - title: 'Keep Markup', - description: 'Prevents custom markup from being dropped out during highlighting.', - owner: 'Golmote', - optional: 'normalize-whitespace', - noCSS: true, - }, - 'command-line': { - title: 'Command Line', - description: - 'Display a command line with a prompt and, optionally, the output/response from the commands.', - owner: 'chriswells0', - }, - 'unescaped-markup': { - title: 'Unescaped Markup', - description: 'Write markup without having to escape anything.', - }, - 'normalize-whitespace': { - title: 'Normalize Whitespace', - description: 'Supports multiple operations to normalize whitespace in code blocks.', - owner: 'zeitgeist87', - optional: 'unescaped-markup', - noCSS: true, - }, - 'data-uri-highlight': { - title: 'Data-URI Highlight', - description: 'Highlights data-URI contents.', - owner: 'Golmote', - noCSS: true, - }, - toolbar: { - title: 'Toolbar', - description: - 'Attach a toolbar for plugins to easily register buttons on the top of a code block.', - owner: 'mAAdhaTTah', - }, - 'copy-to-clipboard': { - title: 'Copy to Clipboard Button', - description: 'Add a button that copies the code block to the clipboard when clicked.', - owner: 'mAAdhaTTah', - require: 'toolbar', - noCSS: true, - }, - 'download-button': { - title: 'Download Button', - description: - 'A button in the toolbar of a code block adding a convenient way to download a code file.', - owner: 'Golmote', - require: 'toolbar', - noCSS: true, - }, - 'match-braces': { - title: 'Match braces', - description: 'Highlights matching braces.', - owner: 'RunDevelopment', - }, - 'diff-highlight': { - title: 'Diff Highlight', - description: 'Highlights the code inside diff blocks.', - owner: 'RunDevelopment', - require: 'diff', - }, - 'filter-highlight-all': { - title: 'Filter highlightAll', - description: - 'Filters the elements the highlightAll and highlightAllUnder methods actually highlight.', - owner: 'RunDevelopment', - noCSS: true, - }, - treeview: { - title: 'Treeview', - description: 'A language with special styles to highlight file system tree structures.', - owner: 'Golmote', - }, - }, -}; diff --git a/packages/astro-prism/src/prism/dependencies.ts b/packages/astro-prism/src/prism/dependencies.ts deleted file mode 100644 index 4cc59d255541..000000000000 --- a/packages/astro-prism/src/prism/dependencies.ts +++ /dev/null @@ -1,460 +0,0 @@ -// This implementation was ported from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/dependencies.js -// biome-ignore-all lint: Ported from the original source as-is -// @ts-nocheck -/* eslint-disable */ - -'use strict'; - -/** - * @typedef {Object} Components - * @typedef {Object} ComponentCategory - * - * @typedef ComponentEntry - * @property {string} [title] The title of the component. - * @property {string} [owner] The GitHub user name of the owner. - * @property {boolean} [noCSS=false] Whether the component doesn't have style sheets which should also be loaded. - * @property {string | string[]} [alias] An optional list of aliases for the id of the component. - * @property {Object} [aliasTitles] An optional map from an alias to its title. - * - * Aliases which are not in this map will the get title of the component. - * @property {string | string[]} [optional] - * @property {string | string[]} [require] - * @property {string | string[]} [modify] - */ - -export var getLoader = (function () { - /** - * A function which does absolutely nothing. - * - * @type {any} - */ - var noop = function () {}; - - /** - * Invokes the given callback for all elements of the given value. - * - * If the given value is an array, the callback will be invokes for all elements. If the given value is `null` or - * `undefined`, the callback will not be invoked. In all other cases, the callback will be invoked with the given - * value as parameter. - * - * @param {null | undefined | T | T[]} value - * @param {(value: T, index: number) => void} callbackFn - * @returns {void} - * @template T - */ - function forEach(value, callbackFn) { - if (Array.isArray(value)) { - value.forEach(callbackFn); - } else if (value != null) { - callbackFn(value, 0); - } - } - - /** - * Returns a new set for the given string array. - * - * @param {string[]} array - * @returns {StringSet} - * - * @typedef {Object} StringSet - */ - function toSet(array) { - /** @type {StringSet} */ - var set = {}; - for (var i = 0, l = array.length; i < l; i++) { - set[array[i]] = true; - } - return set; - } - - /** - * Creates a map of every components id to its entry. - * - * @param {Components} components - * @returns {EntryMap} - * - * @typedef {{ readonly [id: string]: Readonly | undefined }} EntryMap - */ - function createEntryMap(components) { - /** @type {Object>} */ - var map = {}; - - for (var categoryName in components) { - var category = components[categoryName]; - for (var id in category) { - if (id != 'meta') { - /** @type {ComponentEntry | string} */ - var entry = category[id]; - map[id] = typeof entry == 'string' ? { title: entry } : entry; - } - } - } - - return map; - } - - /** - * Creates a full dependencies map which includes all types of dependencies and their transitive dependencies. - * - * @param {EntryMap} entryMap - * @returns {DependencyResolver} - * - * @typedef {(id: string) => StringSet} DependencyResolver - */ - function createDependencyResolver(entryMap) { - /** @type {Object} */ - var map = {}; - var _stackArray = []; - - /** - * Adds the dependencies of the given component to the dependency map. - * - * @param {string} id - * @param {string[]} stack - */ - function addToMap(id, stack) { - if (id in map) { - return; - } - - stack.push(id); - - // check for circular dependencies - var firstIndex = stack.indexOf(id); - if (firstIndex < stack.length - 1) { - throw new Error('Circular dependency: ' + stack.slice(firstIndex).join(' -> ')); - } - - /** @type {StringSet} */ - var dependencies = {}; - - var entry = entryMap[id]; - if (entry) { - /** - * This will add the direct dependency and all of its transitive dependencies to the set of - * dependencies of `entry`. - * - * @param {string} depId - * @returns {void} - */ - function handleDirectDependency(depId) { - if (!(depId in entryMap)) { - throw new Error(id + ' depends on an unknown component ' + depId); - } - if (depId in dependencies) { - // if the given dependency is already in the set of deps, then so are its transitive deps - return; - } - - addToMap(depId, stack); - dependencies[depId] = true; - for (var transitiveDepId in map[depId]) { - dependencies[transitiveDepId] = true; - } - } - - forEach(entry.require, handleDirectDependency); - forEach(entry.optional, handleDirectDependency); - forEach(entry.modify, handleDirectDependency); - } - - map[id] = dependencies; - - stack.pop(); - } - - return function (id) { - var deps = map[id]; - if (!deps) { - addToMap(id, _stackArray); - deps = map[id]; - } - return deps; - }; - } - - /** - * Returns a function which resolves the aliases of its given id of alias. - * - * @param {EntryMap} entryMap - * @returns {(idOrAlias: string) => string} - */ - function createAliasResolver(entryMap) { - /** @type {Object | undefined} */ - var map; - - return function (idOrAlias) { - if (idOrAlias in entryMap) { - return idOrAlias; - } else { - // only create the alias map if necessary - if (!map) { - map = {}; - - for (var id in entryMap) { - var entry = entryMap[id]; - forEach(entry && entry.alias, function (alias) { - if (alias in map) { - throw new Error(alias + ' cannot be alias for both ' + id + ' and ' + map[alias]); - } - if (alias in entryMap) { - throw new Error( - alias + ' cannot be alias of ' + id + ' because it is a component.', - ); - } - map[alias] = id; - }); - } - } - return map[idOrAlias] || idOrAlias; - } - }; - } - - /** - * @typedef LoadChainer - * @property {(before: T, after: () => T) => T} series - * @property {(values: T[]) => T} parallel - * @template T - */ - - /** - * Creates an implicit DAG from the given components and dependencies and call the given `loadComponent` for each - * component in topological order. - * - * @param {DependencyResolver} dependencyResolver - * @param {StringSet} ids - * @param {(id: string) => T} loadComponent - * @param {LoadChainer} [chainer] - * @returns {T} - * @template T - */ - function loadComponentsInOrder(dependencyResolver, ids, loadComponent, chainer) { - var series = chainer ? chainer.series : undefined; - var parallel = chainer ? chainer.parallel : noop; - - /** @type {Object} */ - var cache = {}; - - /** - * A set of ids of nodes which are not depended upon by any other node in the graph. - * - * @type {StringSet} - */ - var ends = {}; - - /** - * Loads the given component and its dependencies or returns the cached value. - * - * @param {string} id - * @returns {T} - */ - function handleId(id) { - if (id in cache) { - return cache[id]; - } - - // assume that it's an end - // if it isn't, it will be removed later - ends[id] = true; - - // all dependencies of the component in the given ids - var dependsOn = []; - for (var depId in dependencyResolver(id)) { - if (depId in ids) { - dependsOn.push(depId); - } - } - - /** - * The value to be returned. - * - * @type {T} - */ - var value; - - if (dependsOn.length === 0) { - value = loadComponent(id); - } else { - // eslint-disable-next-line @typescript-eslint/no-shadow - var depsValue = parallel( - dependsOn.map(function (depId) { - // eslint-disable-next-line @typescript-eslint/no-shadow - var value = handleId(depId); - // none of the dependencies can be ends - delete ends[depId]; - return value; - }), - ); - if (series) { - // the chainer will be responsibly for calling the function calling loadComponent - value = series(depsValue, function () { - return loadComponent(id); - }); - } else { - // we don't have a chainer, so we call loadComponent ourselves - loadComponent(id); - } - } - - // cache and return - return (cache[id] = value); - } - - for (var id in ids) { - handleId(id); - } - - /** @type {T[]} */ - var endValues = []; - for (var endId in ends) { - endValues.push(cache[endId]); - } - return parallel(endValues); - } - - /** - * Returns whether the given object has any keys. - * - * @param {object} obj - */ - function hasKeys(obj) { - for (var key in obj) { - return true; - } - return false; - } - - /** - * Returns an object which provides methods to get the ids of the components which have to be loaded (`getIds`) and - * a way to efficiently load them in synchronously and asynchronous contexts (`load`). - * - * The set of ids to be loaded is a superset of `load`. If some of these ids are in `loaded`, the corresponding - * components will have to reloaded. - * - * The ids in `load` and `loaded` may be in any order and can contain duplicates. - * - * @param {Components} components - * @param {string[]} load - * @param {string[]} [loaded=[]] A list of already loaded components. - * - * If a component is in this list, then all of its requirements will also be assumed to be in the list. - * @returns {Loader} - * - * @typedef Loader - * @property {() => string[]} getIds A function to get all ids of the components to load. - * - * The returned ids will be duplicate-free, alias-free and in load order. - * @property {LoadFunction} load A functional interface to load components. - * - * @typedef { (loadComponent: (id: string) => T, chainer?: LoadChainer) => T} LoadFunction - * A functional interface to load components. - * - * The `loadComponent` function will be called for every component in the order in which they have to be loaded. - * - * The `chainer` is useful for asynchronous loading and its `series` and `parallel` functions can be thought of as - * `Promise#then` and `Promise.all`. - * - * @example - * load(id => { loadComponent(id); }); // returns undefined - * - * await load( - * id => loadComponentAsync(id), // returns a Promise for each id - * { - * series: async (before, after) => { - * await before; - * await after(); - * }, - * parallel: async (values) => { - * await Promise.all(values); - * } - * } - * ); - */ - // eslint-disable-next-line @typescript-eslint/no-shadow - function getLoader(components, load, loaded) { - var entryMap = createEntryMap(components); - var resolveAlias = createAliasResolver(entryMap); - - load = load.map(resolveAlias); - loaded = (loaded || []).map(resolveAlias); - - var loadSet = toSet(load); - var loadedSet = toSet(loaded); - - // add requirements - - load.forEach(addRequirements); - function addRequirements(id) { - var entry = entryMap[id]; - forEach(entry && entry.require, function (reqId) { - if (!(reqId in loadedSet)) { - loadSet[reqId] = true; - addRequirements(reqId); - } - }); - } - - // add components to reload - - // A component x in `loaded` has to be reloaded if - // 1) a component in `load` modifies x. - // 2) x depends on a component in `load`. - // The above two condition have to be applied until nothing changes anymore. - - var dependencyResolver = createDependencyResolver(entryMap); - - /** @type {StringSet} */ - var loadAdditions = loadSet; - /** @type {StringSet} */ - var newIds; - while (hasKeys(loadAdditions)) { - newIds = {}; - - // condition 1) - for (var loadId in loadAdditions) { - var entry = entryMap[loadId]; - forEach(entry && entry.modify, function (modId) { - if (modId in loadedSet) { - newIds[modId] = true; - } - }); - } - - // condition 2) - for (var loadedId in loadedSet) { - if (!(loadedId in loadSet)) { - for (var depId in dependencyResolver(loadedId)) { - if (depId in loadSet) { - newIds[loadedId] = true; - break; - } - } - } - } - - loadAdditions = newIds; - for (var newId in loadAdditions) { - loadSet[newId] = true; - } - } - - /** @type {Loader} */ - var loader = { - getIds: function () { - var ids = []; - loader.load(function (id) { - ids.push(id); - }); - return ids; - }, - load: function (loadComponent, chainer) { - return loadComponentsInOrder(dependencyResolver, loadSet, loadComponent, chainer); - }, - }; - - return loader; - } - - return getLoader; -})(); From da6244c8794ba05c312df547c9d004ec7ef3236f Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 23:15:40 +0900 Subject: [PATCH 07/18] oops --- knip.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/knip.js b/knip.js index 70702de01bc7..39168c079508 100644 --- a/knip.js +++ b/knip.js @@ -54,6 +54,10 @@ export default { '@astrojs/cloudflare', ], }, + 'packages/astro-prism': { + // package.json#imports are not resolved at the moment + ignore: ['src/loadLanguages-workerd.ts'], + }, 'packages/db': { entry: [testEntry, 'test/types/**/*'], }, From 86564b36e031870b34cb5f5ee2d2951c244f020a Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 3 Mar 2026 23:39:04 +0900 Subject: [PATCH 08/18] add explanatory comment --- packages/astro-prism/src/loadLanguages-workerd.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts index 41ba43dc40f1..a017859cb8c5 100644 --- a/packages/astro-prism/src/loadLanguages-workerd.ts +++ b/packages/astro-prism/src/loadLanguages-workerd.ts @@ -1,5 +1,11 @@ // This implementation was based from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components/index.js +// We use dynamic import instead of static import to load the `prismjs` module here. +// Replacing this with a static import can cause instability in the workerd environment, +// occasionally producing the following error: +// "The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response." +// Using dynamic import resolves this instability, so this module must be loaded this way. + const prismLanguageFiles = import.meta.glob('../node_modules/prismjs/components/prism-*.js'); // Since Prism language files are written assuming the Prism instance is defined @@ -13,14 +19,14 @@ function setPrismAsGlobal(prism: typeof import('prismjs')) { }; } -let cache: typeof import('prismjs') | undefined = undefined; +let prismCache: typeof import('prismjs') | undefined = undefined; export async function loadPrism() { - if (!cache) { - ({ default: cache } = await import('prismjs')); + if (!prismCache) { + ({ default: prismCache } = await import('prismjs')); } - return cache; + return prismCache; } /** From 8efd4b2779e934fc23ee7aed688f8729bf110666 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 17 Mar 2026 20:41:57 +0900 Subject: [PATCH 09/18] add `loadChainer` and verify that the language data is loading correctly --- .../astro-prism/src/loadLanguages-workerd.ts | 15 +++++++++- .../test/astro-dev-platform.test.js | 29 ++++++++++++++++++- .../src/pages/prism-test.astro | 3 +- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts index a017859cb8c5..39b18942e4d2 100644 --- a/packages/astro-prism/src/loadLanguages-workerd.ts +++ b/packages/astro-prism/src/loadLanguages-workerd.ts @@ -1,4 +1,5 @@ // This implementation was based from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components/index.js +import type { LoadChainer } from 'prismjs/dependencies.js'; // We use dynamic import instead of static import to load the `prismjs` module here. // Replacing this with a static import can cause instability in the workerd environment, @@ -8,6 +9,18 @@ const prismLanguageFiles = import.meta.glob('../node_modules/prismjs/components/prism-*.js'); +// This `loadChainer` is required when working with Promises in Prism's loader. +// ref: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/dependencies.js#L346-L360 +const loadChainer: LoadChainer> = { + series: async (before, after) => { + await before; + await after(); + }, + parallel: async (values) => { + await Promise.all(values); + }, +}; + // Since Prism language files are written assuming the Prism instance is defined // as a global variable, we will temporarily set the Prism instance globally. function setPrismAsGlobal(prism: typeof import('prismjs')) { @@ -79,7 +92,7 @@ export async function loadLanguages(languages: string | string[]) { } loadedLanguages.add(lang); - }); + }, loadChainer); cleanUp(); } diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.js b/packages/integrations/cloudflare/test/astro-dev-platform.test.js index a35111225e33..0c8ee4a0131b 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.js +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.js @@ -2,15 +2,31 @@ import * as assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import { loadFixture } from './_test-utils.js'; +import { Writable } from 'node:stream'; +import { Logger } from '../../../astro/dist/core/logger/core.js'; describe('AstroDevPlatform', () => { let fixture; let devServer; + const logs = []; + before(async () => { fixture = await loadFixture({ root: './fixtures/astro-dev-platform/', }); - devServer = await fixture.startDevServer(); + devServer = await fixture.startDevServer({ + vite: { logLevel: 'info' }, + logger: new Logger({ + level: 'info', + dest: new Writable({ + objectMode: true, + write(event, _, callback) { + logs.push(event); + callback(); + }, + }), + }), + }); // Do an initial request to prime preloading await fixture.fetch('/'); }); @@ -81,4 +97,15 @@ describe('AstroDevPlatform', () => { // Verify the code block was rendered assert.ok($('pre').length > 0, 'Code block should be rendered'); }); + + it('Prism component loads languages correctly in dev mode', async () => { + const prismUnableToLoadLog = logs.find((log) => + log.message.includes('Unable to load the language'), + ); + + assert.ok( + !prismUnableToLoadLog, + `Should not see "Unable to load the language" message, but got: ${prismUnableToLoadLog?.message}`, + ); + }); }); diff --git a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro index 6ca20bdc9038..c33a2a44673e 100644 --- a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro +++ b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro @@ -7,6 +7,7 @@ import { Prism } from '@astrojs/prism';

Testing Prism Component

- + + From 79d01a349f0bc0b5b47f4c3f41cfa1784d279b05 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 17 Mar 2026 22:46:38 +0900 Subject: [PATCH 10/18] change to use static import and add ``@astro/prism` detection logic to the Cloudflare plugin --- packages/astro-prism/src/highlighter.ts | 5 ++- .../astro-prism/src/loadLanguages-default.ts | 4 --- .../astro-prism/src/loadLanguages-workerd.ts | 30 ++++------------ packages/integrations/cloudflare/src/index.ts | 36 +++++++++++++++++-- 4 files changed, 42 insertions(+), 33 deletions(-) diff --git a/packages/astro-prism/src/highlighter.ts b/packages/astro-prism/src/highlighter.ts index 51e6ae4316c2..908cfa05a626 100644 --- a/packages/astro-prism/src/highlighter.ts +++ b/packages/astro-prism/src/highlighter.ts @@ -1,11 +1,10 @@ -import { loadPrism, loadLanguages } from '#prism-loadLanguages'; +import Prism from 'prismjs'; +import { loadLanguages } from '#prism-loadLanguages'; import { addAstro } from './plugin.js'; const languageMap = new Map([['ts', 'typescript']]); export async function runHighlighterWithAstro(lang: string | undefined, code: string) { - const Prism = await loadPrism(); - if (!lang) { lang = 'plaintext'; } diff --git a/packages/astro-prism/src/loadLanguages-default.ts b/packages/astro-prism/src/loadLanguages-default.ts index e57baf1cebe7..a550403742c9 100644 --- a/packages/astro-prism/src/loadLanguages-default.ts +++ b/packages/astro-prism/src/loadLanguages-default.ts @@ -1,9 +1,5 @@ -import Prism from 'prismjs'; import prismLoadLanguages from 'prismjs/components/index.js'; -export async function loadPrism() { - return Prism; -} export async function loadLanguages(languages: string | string[]) { return prismLoadLanguages(languages); } diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts index 39b18942e4d2..f1efd37a178c 100644 --- a/packages/astro-prism/src/loadLanguages-workerd.ts +++ b/packages/astro-prism/src/loadLanguages-workerd.ts @@ -1,11 +1,7 @@ // This implementation was based from: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/components/index.js -import type { LoadChainer } from 'prismjs/dependencies.js'; - -// We use dynamic import instead of static import to load the `prismjs` module here. -// Replacing this with a static import can cause instability in the workerd environment, -// occasionally producing the following error: -// "The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response." -// Using dynamic import resolves this instability, so this module must be loaded this way. +import Prism from 'prismjs'; +import components from 'prismjs/components.js'; +import getLoader, { type LoadChainer } from 'prismjs/dependencies.js'; const prismLanguageFiles = import.meta.glob('../node_modules/prismjs/components/prism-*.js'); @@ -23,8 +19,8 @@ const loadChainer: LoadChainer> = { // Since Prism language files are written assuming the Prism instance is defined // as a global variable, we will temporarily set the Prism instance globally. -function setPrismAsGlobal(prism: typeof import('prismjs')) { - globalThis.Prism = prism; +function setPrismAsGlobal() { + globalThis.Prism = Prism; return () => { // @ts-expect-error globalThis type @@ -32,16 +28,6 @@ function setPrismAsGlobal(prism: typeof import('prismjs')) { }; } -let prismCache: typeof import('prismjs') | undefined = undefined; - -export async function loadPrism() { - if (!prismCache) { - ({ default: prismCache } = await import('prismjs')); - } - - return prismCache; -} - /** * The set of all languages which have been loaded using the below function. * @@ -58,11 +44,7 @@ const loadedLanguages = new Set(); * @returns {Promise} */ export async function loadLanguages(languages: string | string[]) { - const Prism = await loadPrism(); - const { default: components } = await import('prismjs/components.js'); - const { default: getLoader } = await import('prismjs/dependencies.js'); - - const cleanUp = setPrismAsGlobal(Prism); + const cleanUp = setPrismAsGlobal(); if (languages === undefined) { languages = Object.keys(components.languages).filter((l) => l !== 'meta'); diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 1886b5dbd134..2b1546736e90 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -1,5 +1,5 @@ import { createReadStream, existsSync, readFileSync } from 'node:fs'; -import { appendFile, stat } from 'node:fs/promises'; +import { appendFile, readFile, stat } from 'node:fs/promises'; import { createInterface } from 'node:readline/promises'; import { removeLeadingForwardSlash } from '@astrojs/internal-helpers/path'; import { createRedirectsFromAstroRoutes, printAsRedirects } from '@astrojs/underscore-redirects'; @@ -129,7 +129,7 @@ export default function createIntegration({ return { name: '@astrojs/cloudflare', hooks: { - 'astro:config:setup': ({ command, config, updateConfig, logger, addWatchFile }) => { + 'astro:config:setup': async ({ command, config, updateConfig, logger, addWatchFile }) => { if (!!process.versions.webcontainer) { throw new Error('`workerd` does not run on Stackblitz.'); } @@ -201,6 +201,21 @@ export default function createIntegration({ globalThis.astroCloudflareOptions = cfPluginConfig; } + // Including prismjs files in `optimizeDeps.includes` when `@astrojs/prism` is not installed + // causes a "Failed to resolve dependency: @astrojs/prism > prismjs" log to appear. + // However, when using the `` component in a Cloudflare Workers environment, + // not including prismjs files in `optimizeDeps.includes` causes + // a "The file does not exist at ..." log to appear. + // To work around this, we check whether `@astrojs/prism` is installed in the current project. + // Note: this "Failed to resolve dependency" log will not appear as long as the `@astrojs/prism` package is installed, + // even if it is not actually used. + const prismFiles = [ + '@astrojs/prism > prismjs', + '@astrojs/prism > prismjs/components.js', + '@astrojs/prism > prismjs/dependencies.js', + ] as const; + const isAstroPrismPackageInstalled = await getIsAstroPrismInstalled(config.root); + updateConfig({ build: { redirects: false, @@ -264,6 +279,7 @@ export default function createIntegration({ 'astro/jsx-runtime', 'astro/app/entrypoint/dev', 'astro/virtual-modules/middleware.js', + ...(isAstroPrismPackageInstalled ? prismFiles : []), ], exclude: [ 'unstorage/drivers/cloudflare-kv-binding', @@ -496,3 +512,19 @@ export default function createIntegration({ }, }; } + +// Reads the package.json at the current root to check whether `@astrojs/prism` is installed. +// Using `require.resolve()` would not work correctly for projects inside a monorepo +// (such as Astro's test fixtures), as it would traverse parent node_modules directories +// to resolve the package. For this reason, we directly read `package.json` using `readFile` instead. +async function getIsAstroPrismInstalled(rootURL: URL) { + try { + const pkgURL = new URL('./package.json', rootURL); + const input = await readFile(pkgURL, { encoding: 'utf-8' }); + const pkgJson = JSON.parse(input); + + return Object.hasOwn(pkgJson['dependencies'], '@astrojs/prism'); + } catch { + return false; + } +} From 3b1a04a4f38147c789e1206709caef618ec276f6 Mon Sep 17 00:00:00 2001 From: rururux Date: Thu, 19 Mar 2026 12:07:50 +0900 Subject: [PATCH 11/18] load prism language data files from a virtual module --- .changeset/strict-coats-throw.md | 1 + .../astro-prism/src/loadLanguages-workerd.ts | 9 +-- packages/astro-prism/tsconfig.json | 2 +- packages/astro-prism/virtual.d.ts | 3 + packages/integrations/cloudflare/package.json | 4 +- packages/integrations/cloudflare/src/index.ts | 2 + .../cloudflare/src/vite-plugin-prism.ts | 63 +++++++++++++++++++ pnpm-lock.yaml | 6 ++ 8 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 packages/astro-prism/virtual.d.ts create mode 100644 packages/integrations/cloudflare/src/vite-plugin-prism.ts diff --git a/.changeset/strict-coats-throw.md b/.changeset/strict-coats-throw.md index 699f884eabe0..952e11f2ea08 100644 --- a/.changeset/strict-coats-throw.md +++ b/.changeset/strict-coats-throw.md @@ -1,5 +1,6 @@ --- '@astrojs/prism': patch +'@astrojs/cloudflare': patch --- Fixes an issue where the `` component failed to work in Cloudflare Workers. diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts index f1efd37a178c..64d8dfdad1ce 100644 --- a/packages/astro-prism/src/loadLanguages-workerd.ts +++ b/packages/astro-prism/src/loadLanguages-workerd.ts @@ -2,8 +2,7 @@ import Prism from 'prismjs'; import components from 'prismjs/components.js'; import getLoader, { type LoadChainer } from 'prismjs/dependencies.js'; - -const prismLanguageFiles = import.meta.glob('../node_modules/prismjs/components/prism-*.js'); +import { bundledLanguages } from 'virtual:astro-cloudflare:prism'; // This `loadChainer` is required when working with Promises in Prism's loader. // ref: https://github.com/PrismJS/prism/blob/76dde18a575831c91491895193f56081ac08b0c5/dependencies.js#L346-L360 @@ -64,13 +63,11 @@ export async function loadLanguages(languages: string | string[]) { return; } - const pathToLanguage = `../node_modules/prismjs/components/prism-${lang}.js`; - // remove from Prism delete Prism.languages[lang]; - if (Object.hasOwn(prismLanguageFiles, pathToLanguage)) { - await prismLanguageFiles[pathToLanguage](); + if (Object.hasOwn(bundledLanguages, lang)) { + await bundledLanguages[lang](); } loadedLanguages.add(lang); diff --git a/packages/astro-prism/tsconfig.json b/packages/astro-prism/tsconfig.json index 34c71757b6f0..84828abf287d 100644 --- a/packages/astro-prism/tsconfig.json +++ b/packages/astro-prism/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "../../tsconfig.base.json", - "include": ["src"], + "include": ["src", "virtual.d.ts"], "compilerOptions": { "rootDir": "./src", "outDir": "./dist", diff --git a/packages/astro-prism/virtual.d.ts b/packages/astro-prism/virtual.d.ts new file mode 100644 index 000000000000..ee8f267e410b --- /dev/null +++ b/packages/astro-prism/virtual.d.ts @@ -0,0 +1,3 @@ +declare module 'virtual:astro-cloudflare:prism' { + export const bundledLanguages: Record Promise>; +} diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index e8e92fb381a9..88c3a56d6508 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -59,7 +59,9 @@ "astro": "workspace:*", "astro-scripts": "workspace:*", "cheerio": "1.2.0", - "devalue": "^5.6.3" + "devalue": "^5.6.3", + "prismjs": "^1.30.0", + "@types/prismjs": "1.26.6" }, "publishConfig": { "provenance": true diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 2b1546736e90..06c921213a99 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -22,6 +22,7 @@ import { import { parseEnv } from 'node:util'; import { sessionDrivers } from 'astro/config'; import { createCloudflarePrerenderer } from './prerenderer.js'; +import cfPrismPlugin from './vite-plugin-prism.js'; const CLOUDFLARE_KV_SESSION_DRIVER_ENTRYPOINT = sessionDrivers.cloudflareKVBinding().entrypoint; @@ -334,6 +335,7 @@ export default function createIntegration({ } : null, }), + cfPrismPlugin(), ], }, image: setImageConfig(imageService, config.image, command, logger), diff --git a/packages/integrations/cloudflare/src/vite-plugin-prism.ts b/packages/integrations/cloudflare/src/vite-plugin-prism.ts new file mode 100644 index 000000000000..a65e99defb18 --- /dev/null +++ b/packages/integrations/cloudflare/src/vite-plugin-prism.ts @@ -0,0 +1,63 @@ +import { fileURLToPath } from 'node:url'; +import type { Plugin } from 'vite'; +import components from 'prismjs/components.js'; + +const MODULE_ID = 'virtual:astro-cloudflare:prism'; +const RESOLVED_MODULE_ID = '\0' + MODULE_ID; + +const languages = Object.keys(components.languages).filter((l) => l !== 'meta'); + +export default function cfPrismPlugin(): Plugin { + return { + name: '@astrojs/cloudflare:prism', + configEnvironment(environmentName) { + if (environmentName === 'ssr') { + return { + // Because this virtual module adds a large number of dynamic import statements, + // Vite’s logs will consequently display the message “new dependencies optimized” for all languages. + // To avoid this, we explicitly specify that the module should be optimized in advance. + optimizeDeps: { + include: ['prismjs/components/prism-*.js'], + }, + }; + } + }, + resolveId: { + filter: { + id: new RegExp(`^${MODULE_ID}$`), + }, + handler() { + return RESOLVED_MODULE_ID; + }, + }, + load: { + filter: { + id: new RegExp(`^${RESOLVED_MODULE_ID}$`), + }, + async handler() { + const importerPath = fileURLToPath(import.meta.url); + + const resolvedModules = await Promise.all( + languages.map(async (lang) => { + const resolvedId = await this.resolve( + `prismjs/components/prism-${lang}.js`, + importerPath, + ); + + return { resolvedId: resolvedId?.id, lang }; + }), + ); + const prismBundledLanguages = resolvedModules + .filter(({ resolvedId }) => resolvedId !== undefined) + .map( + ({ resolvedId, lang }) => + `${JSON.stringify(lang)}: () => import(${JSON.stringify(resolvedId)})`, + ); + + return ` + export const bundledLanguages = { ${prismBundledLanguages.join(',')} }; + `; + }, + }, + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05ead36cf64e..ee2578414e48 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4916,6 +4916,9 @@ importers: '@types/node': specifier: ^25.2.2 version: 25.2.3 + '@types/prismjs': + specifier: 1.26.6 + version: 1.26.6 astro: specifier: workspace:* version: link:../../astro @@ -4928,6 +4931,9 @@ importers: devalue: specifier: ^5.6.3 version: 5.6.3 + prismjs: + specifier: ^1.30.0 + version: 1.30.0 packages/integrations/cloudflare/test/fixtures/astro-dev-platform: dependencies: From 37b971fe58d68ec6cb6c7093e52d72733cbedba4 Mon Sep 17 00:00:00 2001 From: rururux Date: Thu, 19 Mar 2026 12:23:29 +0900 Subject: [PATCH 12/18] remove vite from astro-prism's dependencies --- packages/astro-prism/package.json | 3 +-- packages/astro-prism/tsconfig.json | 3 +-- pnpm-lock.yaml | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/astro-prism/package.json b/packages/astro-prism/package.json index f0f33a241f28..1c643c94e500 100644 --- a/packages/astro-prism/package.json +++ b/packages/astro-prism/package.json @@ -42,8 +42,7 @@ }, "devDependencies": { "@types/prismjs": "1.26.6", - "astro-scripts": "workspace:*", - "vite": "^7.3.1" + "astro-scripts": "workspace:*" }, "engines": { "node": "^20.19.1 || >=22.12.0" diff --git a/packages/astro-prism/tsconfig.json b/packages/astro-prism/tsconfig.json index 84828abf287d..1337aa2b7110 100644 --- a/packages/astro-prism/tsconfig.json +++ b/packages/astro-prism/tsconfig.json @@ -3,7 +3,6 @@ "include": ["src", "virtual.d.ts"], "compilerOptions": { "rootDir": "./src", - "outDir": "./dist", - "types": ["vite/client"] + "outDir": "./dist" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee2578414e48..063dcb9f36d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -786,9 +786,6 @@ importers: astro-scripts: specifier: workspace:* version: link:../../scripts - vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2) packages/astro-rss: dependencies: From 782794cb0b234428683c9401654cf5f643a9ddef Mon Sep 17 00:00:00 2001 From: rururux Date: Fri, 1 May 2026 20:50:59 +0900 Subject: [PATCH 13/18] update test --- .../integrations/cloudflare/test/astro-dev-platform.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.ts b/packages/integrations/cloudflare/test/astro-dev-platform.test.ts index c02bf68d4e92..e77ffc5a25db 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.ts +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.ts @@ -3,7 +3,7 @@ import { after, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import { type DevServer, type Fixture, loadFixture } from './test-utils.ts'; import { Writable } from 'node:stream'; -import { Logger } from '../../../astro/dist/core/logger/core.js'; +import { AstroLogger } from '../../../astro/dist/core/logger/core.js'; describe('AstroDevPlatform', () => { let fixture: Fixture; @@ -16,9 +16,9 @@ describe('AstroDevPlatform', () => { }); devServer = await fixture.startDevServer({ vite: { logLevel: 'info' }, - logger: new Logger({ + logger: new AstroLogger({ level: 'info', - dest: new Writable({ + destination: new Writable({ objectMode: true, write(event, _, callback) { logs.push(event); From 8994f9715745baaaa44b3675fd4f885d057a3fde Mon Sep 17 00:00:00 2001 From: rururux Date: Fri, 1 May 2026 21:30:55 +0900 Subject: [PATCH 14/18] fix type error --- .../integrations/cloudflare/test/astro-dev-platform.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.ts b/packages/integrations/cloudflare/test/astro-dev-platform.test.ts index e77ffc5a25db..e03030ad6a91 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.ts +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.ts @@ -3,12 +3,12 @@ import { after, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; import { type DevServer, type Fixture, loadFixture } from './test-utils.ts'; import { Writable } from 'node:stream'; -import { AstroLogger } from '../../../astro/dist/core/logger/core.js'; +import { AstroLogger, type AstroLoggerMessage } from '../../../astro/dist/core/logger/core.js'; describe('AstroDevPlatform', () => { let fixture: Fixture; let devServer: DevServer; - const logs = []; + const logs: AstroLoggerMessage[] = []; before(async () => { fixture = await loadFixture({ @@ -16,6 +16,7 @@ describe('AstroDevPlatform', () => { }); devServer = await fixture.startDevServer({ vite: { logLevel: 'info' }, + // @ts-expect-error: `logger` is an internal API logger: new AstroLogger({ level: 'info', destination: new Writable({ From d187c793d4b3f1f1b46ddbfd688748b5e12d0cf2 Mon Sep 17 00:00:00 2001 From: rururux Date: Tue, 5 May 2026 01:59:32 +0900 Subject: [PATCH 15/18] improve stability when multiple `` components are used --- .../astro-prism/src/loadLanguages-workerd.ts | 35 ++++++++++++++----- .../test/astro-dev-platform.test.ts | 3 +- .../src/pages/prism-test.astro | 7 ++-- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/packages/astro-prism/src/loadLanguages-workerd.ts b/packages/astro-prism/src/loadLanguages-workerd.ts index 64d8dfdad1ce..fa30436a7935 100644 --- a/packages/astro-prism/src/loadLanguages-workerd.ts +++ b/packages/astro-prism/src/loadLanguages-workerd.ts @@ -18,14 +18,31 @@ const loadChainer: LoadChainer> = { // Since Prism language files are written assuming the Prism instance is defined // as a global variable, we will temporarily set the Prism instance globally. -function setPrismAsGlobal() { - globalThis.Prism = Prism; +// As loadLanguages can be called asynchronously multiple times, there is a risk +// that globalThis.Prism may be accessed again after cleanup, even when it appears +// to be no longer needed after a Promise resolves, potentially causing a +// `Prism is not defined` error. +// To avoid this, we track the number of active references and only perform cleanup +// when the count returns to zero. +let prismRefCount = 0; - return () => { - // @ts-expect-error globalThis type - delete globalThis.Prism; - }; -} +const prismRefCounter = { + increment: () => { + if (prismRefCount === 0) { + globalThis.Prism = Prism; + } + + prismRefCount += 1; + }, + decrement: () => { + prismRefCount -= 1; + + if (prismRefCount === 0) { + // @ts-expect-error globalThis type + delete globalThis.Prism; + } + }, +}; /** * The set of all languages which have been loaded using the below function. @@ -43,7 +60,7 @@ const loadedLanguages = new Set(); * @returns {Promise} */ export async function loadLanguages(languages: string | string[]) { - const cleanUp = setPrismAsGlobal(); + prismRefCounter.increment(); if (languages === undefined) { languages = Object.keys(components.languages).filter((l) => l !== 'meta'); @@ -73,7 +90,7 @@ export async function loadLanguages(languages: string | string[]) { loadedLanguages.add(lang); }, loadChainer); - cleanUp(); + prismRefCounter.decrement(); } /** diff --git a/packages/integrations/cloudflare/test/astro-dev-platform.test.ts b/packages/integrations/cloudflare/test/astro-dev-platform.test.ts index e03030ad6a91..56bc79479d4c 100644 --- a/packages/integrations/cloudflare/test/astro-dev-platform.test.ts +++ b/packages/integrations/cloudflare/test/astro-dev-platform.test.ts @@ -96,7 +96,8 @@ describe('AstroDevPlatform', () => { // Verify the page rendered successfully with Prism component assert.equal($('h1').text(), 'Testing Prism Component'); // Verify the code block was rendered - assert.ok($('pre').length > 0, 'Code block should be rendered'); + // 'css', 'js', 'ts', and 'rust' + assert.equal($('pre').length, 4, 'Code block should be rendered'); }); it('Prism component loads languages correctly in dev mode', async () => { diff --git a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro index c33a2a44673e..cc63cede5616 100644 --- a/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro +++ b/packages/integrations/cloudflare/test/fixtures/astro-dev-platform/src/pages/prism-test.astro @@ -7,7 +7,10 @@ import { Prism } from '@astrojs/prism';

Testing Prism Component

- - + + + + + From f63e1cfe2e69d8b782fe48fd232e0c33bd4bc961 Mon Sep 17 00:00:00 2001 From: rururux Date: Thu, 7 May 2026 19:13:44 +0900 Subject: [PATCH 16/18] update `tsconfig.build.json` --- packages/astro-prism/tsconfig.build.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/astro-prism/tsconfig.build.json b/packages/astro-prism/tsconfig.build.json index 79fbbc66db11..44dc5f25ead3 100644 --- a/packages/astro-prism/tsconfig.build.json +++ b/packages/astro-prism/tsconfig.build.json @@ -1,3 +1,4 @@ { - "extends": "../../configs/tsconfig.build.json" + "extends": "../../configs/tsconfig.build.json", + "include": ["./src", "./virtual.d.ts"] } From ea86b2b8a72a139934f205e41b35cf64d9e5af70 Mon Sep 17 00:00:00 2001 From: rururux Date: Thu, 7 May 2026 19:24:12 +0900 Subject: [PATCH 17/18] fix knip lint --- knip.js | 1 + 1 file changed, 1 insertion(+) diff --git a/knip.js b/knip.js index 9693c37ad92c..53f801438d4e 100644 --- a/knip.js +++ b/knip.js @@ -60,6 +60,7 @@ export default { ], }, 'packages/astro-prism': { + entry: [srcEntry, dtsEntry, testEntry], // package.json#imports are not resolved at the moment ignore: ['src/loadLanguages-workerd.ts'], }, From 1e1d7168fef6b6dd8796339427b63ff957f1c00b Mon Sep 17 00:00:00 2001 From: rururux Date: Thu, 7 May 2026 19:25:44 +0900 Subject: [PATCH 18/18] format --- packages/astro-prism/tsconfig.build.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro-prism/tsconfig.build.json b/packages/astro-prism/tsconfig.build.json index 44dc5f25ead3..0df1179de9b9 100644 --- a/packages/astro-prism/tsconfig.build.json +++ b/packages/astro-prism/tsconfig.build.json @@ -1,4 +1,4 @@ { "extends": "../../configs/tsconfig.build.json", - "include": ["./src", "./virtual.d.ts"] + "include": ["./src", "./virtual.d.ts"] }