summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/workers/syntax-worker.ts
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/workers/syntax-worker.ts')
-rw-r--r--polygerrit-ui/app/workers/syntax-worker.ts84
1 files changed, 84 insertions, 0 deletions
diff --git a/polygerrit-ui/app/workers/syntax-worker.ts b/polygerrit-ui/app/workers/syntax-worker.ts
new file mode 100644
index 0000000000..1ddb9c67dd
--- /dev/null
+++ b/polygerrit-ui/app/workers/syntax-worker.ts
@@ -0,0 +1,84 @@
+/**
+ * @license
+ * Copyright 2022 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import {HighlightJS} from '../types/types';
+import {
+ SyntaxWorkerMessage,
+ SyntaxWorkerResult,
+ isRequest,
+ isInit,
+} from '../types/syntax-worker-api';
+import {highlightedStringToRanges} from '../utils/syntax-util';
+import {importScript} from '../utils/worker-util';
+
+// This is an entry point file of a bundle. Keep free of exports!
+
+/**
+ * This is a web worker for calling the HighlightJS library for syntax
+ * highlighting. Files can be large and highlighting does not require
+ * the `document` or the `DOM`, so it is a perfect fit for a web worker.
+ *
+ * This file is a just a hub hooking into the web worker API. The message
+ * events for communicating with the main app are defined in the file
+ * `types/worker-api.ts`. And the `meat` of the computation is done in the
+ * file `syntax-util.ts`.
+ */
+
+/**
+ * `self` is for a worker what `window` is for the web app. It is called
+ * the `DedicatedWorkerGlobalScope`, see
+ * https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope
+ *
+ * Once imported the HighlightJS lib exposes its functionality via the global
+ * `hljs` variable.
+ */
+const ctx = self as DedicatedWorkerGlobalScope & {hljs?: HighlightJS};
+
+/**
+ * We are encapsulating the web worker API here, so this is the only place
+ * where you need to know about it and the MessageEvents in this file.
+ */
+ctx.onmessage = function (e: MessageEvent<SyntaxWorkerMessage>) {
+ try {
+ const message = e.data;
+ if (isInit(message)) {
+ worker.init(message.url);
+ const result: SyntaxWorkerResult = {ranges: []};
+ ctx.postMessage(result);
+ }
+ if (isRequest(message)) {
+ const ranges = worker.highlightCode(message.language, message.code);
+ const result: SyntaxWorkerResult = {ranges};
+ ctx.postMessage(result);
+ }
+ } catch (err) {
+ let error = 'syntax worker error';
+ if (err instanceof Error) error = err.message;
+ const result: SyntaxWorkerResult = {error, ranges: []};
+ ctx.postMessage(result);
+ }
+};
+
+class SyntaxWorker {
+ private highlightJsLib?: HighlightJS;
+
+ init(highlightJsLibUrl: string) {
+ importScript(ctx, highlightJsLibUrl);
+ if (!ctx.hljs) {
+ throw new Error('HighlightJS lib not available after import');
+ }
+ this.highlightJsLib = ctx.hljs;
+ this.highlightJsLib.configure({classPrefix: ''});
+ }
+
+ highlightCode(language: string, code: string) {
+ if (!this.highlightJsLib) throw new Error('worker not initialized');
+ const highlighted = this.highlightJsLib.highlight(language, code, true);
+ return highlightedStringToRanges(highlighted.value);
+ }
+}
+
+/** Singleton instance being referenced in `onmessage` function above. */
+const worker = new SyntaxWorker();